function parseInstructionPages(instructionPage1, instructionPage2, instructionPage3, customInstructionPage){
	instructionPage1 = instructionPage1.replace(/'/g, "&apos;");
	instructionPage2 = instructionPage2.replace(/'/g, "&apos;");
	instructionPage3 = instructionPage3.replace(/'/g, "&apos;");
	customInstructionPage = customInstructionPage.replace(/'/g, "&apos;");
}

function BuildModuleTree(r){		
	// make sure the tree is only constructed once
    var m = Ext.getCmp('modTree');
	if (m && m.created) {
	    return null;
	}
			
	// create the navigation tree and pass it all nodes to be loaded
    var modTree = Ext.create('Kaseya.web.widgets.navigation.KNavigationTree');	
    modTree.addNodes(r);				
	modTree.created = true;
    				
	return modTree;
}

function BuildBookmarksTree(r, tb) {		
    var cp = Ext.getCmp('CenterPanel');
	
	var bmTree = new Ext.tree.TreePanel({
	    rootVisible: false,
	    bodyBorder: false,
	    border: false,
	    tbar: tb || false,
	    autoScroll: true,
	    id: 'bmTree',	
	    stateful: false,	
	    store: Ext.create('Ext.data.TreeStore', {
	        model: Ext.ModelManager.getModel('Kaseya.models.tree.NavigationBookmarkNode'),
	        root: {
	            text: '',
	            expanded: true            
	        },
	        proxy: {
	            type: 'memory'
	        }
	    }),
        listeners: {
			'beforeitemclick': function(view, _node, item, index, _event){
				if (_node.data.moduleNodeType === 'FOLDER') {					
				    _node.isExpanded() ? _node.collapse() :_node.expand();
					return false;
				}
		    },	        
	        'itemclick': {
		        fn: OnGetScreen,
		        scope: cp,
		        buffer: PageMgrFinder().getModel('user_store', 'user_store').defermentInterval
	        }, scope: cp               
        }
	});
	
	var bmConfig = {
	    text: 'Bookmarks',
	    children: [],
	    expanded: true,
        leaf: false,
        moduleNodeType: 'FOLDER'		    
	};
	
	Ext.each(r.folders, function(folder) {
        var f = {
            text: folder.name,
            description: folder.description,
            funcListID: folder.funcListID,
            helpId: folder.helpId,
            instructionId: folder.instructionId,
            name: folder.name,
            children: [],
            leaf: false,
            moduleNodeType: 'FOLDER'
        };
        
        Ext.each(folder.items, function(item) {
            var i = {
                text: item.name,
                description: item.description,
                funcListID: item.funcListID,
                helpId: item.helpId,
                instructionId: item.instructionId,
                name: item.name,
                leaf: true,
                moduleNodeType: 'BOOKMARK',
                dataProvider: MessageSysProvider,
                iconCls: 'x-tree-noicon'
            };
            
            f.children.push(i);            
        }, this);
        
        bmConfig.children.push(f);
	}, this);
	
	bmTree.getRootNode().appendChild(bmConfig); 
	
	return bmTree;
}

function CleanAndCloseAction(_windowId){
	if (Ext.getCmp(_windowId)) {
		// clean the island before we close the window
		PageMgrFinder().manuallyCleanIsland(_windowId, _windowId);
		Ext.getCmp(_windowId).close();
	}
}

function NavigateAwayItemHandler(_btn){
	if (_btn == "no" || _btn == "cancel") {
		return false;
	}
	else {
		// Find any open actions, and close them
		CleanAndCloseAction(PageMgrFinder().pageDirty());
		
        PageMgrFinder().pageDirty(false);
        NavigateTo({ activeId: this.data.funcListID});
	}
}

function NavigateAwayToHandler(_btn){
    if (_btn == "no" || _btn == "cancel") {
		return false;
	}
	else {
		// Find any open actions, and close them
		CleanAndCloseAction(PageMgrFinder().pageDirty());
		PageMgrFinder().pageDirty(false);
		NavigateTo(this);
	}
}

function NavigateAwayModuleHandler(_btn){
	if (_btn == "no" || _btn == "cancel") {
		return false;
	}
	else {
		// Find any open actions, and close them
		CleanAndCloseAction(PageMgrFinder().pageDirty());
		PageMgrFinder().pageDirty(false);
		LoadModule(this);
	}
}

function NavigateAwayModuleClickHandler(_btn){
	if (_btn == "no" || _btn == "cancel") {
		return false;
	}
	else {
		// find any open actions, and close them
		CleanAndCloseAction(PageMgrFinder().pageDirty());
		PageMgrFinder().pageDirty(false);
		LoadModuleClick(this);
	}
}

/**
 * Creates the application viewport and essential child panels
 * @param {Boolean} _contextScreenOnly 
 * @param {Boolean} _recorder
 * @param {Number} _siteHeaderHeight 
 */
function BuildPage(_contextScreenOnly, _recorder, _siteHeaderHeight){    
    Ext.application({
        name: 'Kaseya',
        launch: function() {                       
            if (_contextScreenOnly) {	    
                Ext.create('Ext.container.Viewport', {
			        id: 'PageShellViewPort',
			        layout: 'border',            
                    items: [{
                        xtype: 'NavigationControl',
                        width: 0,
                        minNavigatorWidth: 0,				    
                        collapsible: true,
                        header: false,
                        PAGE_ID: PAGE_ID,
                        WEB_WINDOW_ID: WEB_WINDOW_ID,
                        UNAUTHENTICATED_URL: UNAUTHENTICATED_URL,
                        AUTHENTICATED_URL: AUTHENTICATED_URL,
                        HELP_URL: HELP_URL,
                        FORM_URL: FORM_URL,
                        ACTION_URL: ACTION_URL
                    }, {
                        region: 'center',
                        id: 'CenterPanel',
                        itemId: 'CenterPanel',
                        border: true,
                        collapsible: false,
                        split: false,
                        layout: 'card'
                    }
                ]});                                
            }
            else if (_recorder) {	
                Ext.create('Ext.container.Viewport', {
			        id: 'PageShellViewPort',
			        layout: 'border',            
                    items: [{ 
	                    xtype: 'BannerBar', 
	                    hidden: _contextScreenOnly, 
	                    siteHeaderHeight: _siteHeaderHeight
	                }, {
                        collapsible: true,
                        header: false,
                        PAGE_ID: PAGE_ID,
                        WEB_WINDOW_ID: WEB_WINDOW_ID,
                        UNAUTHENTICATED_URL: UNAUTHENTICATED_URL,
                        AUTHENTICATED_URL: AUTHENTICATED_URL,
                        HELP_URL: HELP_URL,
                        FORM_URL: FORM_URL,
                        ACTION_URL: ACTION_URL,
                        xtype: 'NavigationControl'
                    }, {
		                region: 'center',
		                id: 'CenterPanel',
		                itemId: 'CenterPanel',
		                border: true,
		                collapsible: false,
		                split: false,
		                layout: 'card'
	                }, {
		                region: 'south',
		                id: 'RecorderPanel',
		                itemId: 'RecorderPanel',
		                border: false,
		                bodyBorder: false,
		                collapsible: false,
		                split: false,
		                layout: 'fit',
		                height: 30,
		                items: { xtype: 'krecorderpanel' }
	                }
                ]});
	        }
            else {					
                // configure the "inside" border layout
                var panel = [{
	                    xtype: 'NavigationControl',
	                    collapsible: true,
	                    header: false,
	                    PAGE_ID: PAGE_ID,
	                    WEB_WINDOW_ID: WEB_WINDOW_ID,
	                    UNAUTHENTICATED_URL: UNAUTHENTICATED_URL,
	                    AUTHENTICATED_URL: AUTHENTICATED_URL,
	                    HELP_URL: HELP_URL,
	                    FORM_URL: FORM_URL,
	                    ACTION_URL: ACTION_URL
                    }, {
		                region: 'center',
		                id: 'CenterPanel',
		                itemId: 'CenterPanel',
		                border: true,
		                collapsible: false,
		                split: false,
		                layout: 'card'
	                }                    
                ];

                var eastPanelInline = true;
                if (eastPanelInline) {
                    panel.push({
                        region: 'east',
                        collapsible: true,
                        collapsed: false,
                        layout: 'fit',
                        id: 'Dashbar',
                        title: 'Dashbar', // TODO: translation
                        width: 306,
                        hidden: true,
                        stateKey: 'dashbar',
                        items: [{
                            xtype: 'kdashboardlayout',
                            conduit: 'TestModule',
                            plugin: 'Kaseya.TestModule',
                            className: 'Dashboards40',
                            collapseMode: 'header',
                            guid: '0',
                            showTitleInChart: true,
                            suppressHeader: true
                        }],
                        listeners: {
                            stateLoaded: function(panel) {
                                var state = Ext.state.Manager.get(panel.stateKey);
                                if (Ext.isDefined(state) && state != null) {
                                    if (state === true) {                                                                                
                                        panel.collapse(); // this collapses and shows the dashbar
                                    }
                                }
                            },
                            expand: function(){
                                this.doLayout();
                            }
                        }                    
                    });
                }

                // configure the "outside" border layout
                var vpItems = [{ 
	                    xtype: 'BannerBar', 
	                    hidden: _contextScreenOnly, 
	                    siteHeaderHeight: _siteHeaderHeight
	                },
                    {
                        region: 'center',
                        id: 'mainCenter',
                        layout: 'border',
                        items: panel,
                        border: false
                    }];

                var eastPanelOver = false;
                if (!eastPanelInline && eastPanelOver) {
                    vpItems.push({
                        region: 'east',                        
                        collapsible: true,
                        collapsed: true,
                        title: 'Dashbar', // TODO: translation
                        id: 'Dashbar',
                        width: '86%',
                        items: [{
                            xtype: 'kdashboardlayout',
                            conduit: 'TestModule',
                            plugin: 'Kaseya.TestModule',
                            className: 'Dashboards40',
                            collapseMode: 'header',
                            guid: '0'
                        }],
                        listeners: {
                            expand: function(){
                                this.doLayout();
                            }
                        } 
                    });        
                }

                Ext.create('Ext.container.Viewport', {
			        id: 'PageShellViewPort',
                    layout: 'fit',			                    
                    items: [
                        {
                            tbar: Ext.create('Kaseya.web.widgets.navigation.KNotificationBar'),
                            id: 'PageShellViewPortPanel',
                            layout: 'border',
                            items: vpItems,
                            border: false,
                            bodyBorder: false
                        }
                    ]
                });
            }	                        
        }
    });			
}

/**
 * Opens the legacy chat window if a user is requesting to chat with an administrator.
 * @param {Object} _adChatId
 * @param {Object} _chatId
 * @param {Object} _snd
 * @param {Object} _autoClose
 */
function OpenChatWindow( _adChatId, _chatId, _snd, _autoClose ){
	window.open("/HelpDeskTab/sessionAdChatFrame.asp?adChatId="+_adChatId+
        "&chatId="+_chatId+"&snd="+_snd+"&autoClose="+_autoClose+"&"+String(Math.random()).substr(2,6),
        "chat"+_chatId,"dependent,toolbar=no,resizable=yes,scrollbars=no,width=500,height=500");
}

/**
 * Handles if a controller is clicked.  If there is a pre-controller to be run, 
 * then that will be run appropriately, otherwise the controller will be passed to the proper
 * behavior choosing mechanism in the ControllerCommandHandler function.
 * @param {Object} _btnClicked
 */
function ControllerClickHandler(_btnClicked){
	if (_btnClicked.initialConfig.controllerConfiguration.behavior == "CANCEL") {
		if (Ext.WindowManager.get(_btnClicked.pageId)) {
			Ext.WindowManager.get(_btnClicked.pageId).close();
        } else if (window.opener) {
			// its a classic window
			window.close();
        }
		
        return;
	}
	
	if (!_btnClicked.initialConfig.controllerConfiguration.itemFuncListId) {
		_btnClicked.initialConfig.controllerConfiguration.itemFuncListId = PageMgrFinder().getModel('user_store', 'user_store').currentLoadConfig.activeId;
    }
	
	// check if the action command has a preaction.  If so, run that first
	if (_btnClicked.initialConfig && _btnClicked.initialConfig.controllerConfiguration && _btnClicked.initialConfig.controllerConfiguration.PreController) {
		//if we have a pre_action, then we need to set it up and return from this method before calling into the ActionCommandHandler		
		var preaction = _btnClicked.initialConfig.controllerConfiguration.PreController;
		switch (preaction.type) {
			case "PreControllerYesNo":
				var btnObj = Ext.Msg.YESNO;
				if (Ext.isString(preaction.NoText) && Ext.isString(preaction.YesText)) {
					btnObj = {
						yes: preaction.YesText,
						no: preaction.NoText
					};
				}

				Ext.Msg.show({
					title: preaction.title,
					msg: preaction.text,
					buttons: btnObj,
					animEl: Ext.get(_btnClicked.id),
					icon: Ext.Msg.QUESTION,
					scope: _btnClicked,
					fn: ControllerPreCommandHandler
				});
				break;
				
			case "PreControllerYesNoCancel":
				var btnObj = Ext.Msg.YESNOCANCEL;
				if (Ext.isString(preaction.NoText) && Ext.isString(preaction.YesText) && Ext.isString(preaction.CancelText)) {
					btnObj = {
						yes: preaction.YesText,
						no: preaction.NoText,
						cancel: preaction.CancelText
					};
				}
				Ext.Msg.show({
					title: preaction.title,
					msg: preaction.text,
					buttons: btnObj,
					animEl: Ext.get(_btnClicked.id),
					icon: Ext.Msg.QUESTION,
					scope: _btnClicked,
					fn: ControllerPreCommandHandler
				});
				break;
				
			case "PreControllerPrompt":
				Ext.Msg.prompt(preaction.title, preaction.text, ControllerPreCommandHandler, _btnClicked);
				break;
				
			case "PreControllerAlert":
				Ext.Msg.alert(preaction.title, preaction.text);
				break;
				
			default:
				AddDebugger();
				break;
		}
		
        return;
	}
	
    ControllerCommandHandler(_btnClicked);
}


/**
 * Pre command handler that if configured will confirm that the user really wants to do what they are about to do
 * prior to running the controller that could potentially make them loose information.
 * @param {Object} _btn
 * @param {Object} _text
 */
function ControllerPreCommandHandler(_btn, _text){
	// if the preaction was confirmed, then we need to handle the action.
	if (_btn == "ok" || _btn == "yes") {
		if (this.initialConfig.controllerConfiguration.PreController.type == "PreControllerPrompt") {
			this.initialConfig.preactionInputValue = _text;
		}
		
		if (this.initialConfig.controllerConfiguration.PreController.type == "PreControllerYesNoCancel") {
			this.initialConfig.preactionAffirmativeResponse = true;
		}
		
		ControllerCommandHandler(this);
	}
	else 
		if (_btn == "no" && this.initialConfig.controllerConfiguration.PreController.type == "PreControllerYesNoCancel") {
			this.initialConfig.preactionAffirmativeResponse = false;
			ControllerCommandHandler(this);
		}
		else {
		    //else we didn't get a confirmation
		    //do nothing, just return to the screen after closing the pre-action window
		}
}


/**
 * Determines which controller to run based on the behavior of the current button clicked.
 * If the button should start, then a window is launched and the controller is started.
 * If the button should continue, then the same controller is called that started the window's action.
 * @param {Object} _btnClicked
 * @param {Object} _markedObjects
 */
function ControllerCommandHandler(_btnClicked, _markedObjects, _sticky){
	if (_btnClicked.initialConfig.controllerConfiguration.behavior == "START") {
		ControllerStart(_btnClicked, _markedObjects, _sticky);
	}
	else if (_btnClicked.initialConfig.controllerConfiguration.behavior == "CONTINUE") {
        // get a reference to the containing form and validate it before continuing with the "CONTINUE" request
        var form = _btnClicked.findParentByType('kform');        
        if (!form) {
            var win = _btnClicked.findParentByType('kcontrollerwindow');
            if (win) {
                form = win.findByType('kform');
                if (form.length > 0) {
                    form = form[0];
                }
            }
        }
        
        var validateForm = _btnClicked.controllerConfiguration && convertToBool(_btnClicked.controllerConfiguration.validate);
        if (!_btnClicked.xtype && form && form.getForm && form.getForm() && validateForm) {
            if (!form.getForm().isValid()) {
                showMessageBox('', Ext.ux.LangMgr.KFlowchart.errorsExist, Ext.Msg.ERROR);
                
                return;
            }
        }
		
		if (Ext.isIE) { // kerbe: IE8 doesn't wait for grid editing events to finish completely on a controller continue (such as a save), so introduce a slight delay to make events happen in the correct sequence
		    setTimeout(
		        function() {
		            ControllerContinue(_btnClicked.initialConfig, _markedObjects);
		        }, 50
		    );
		} else {
		    ControllerContinue(_btnClicked.initialConfig, _markedObjects);
		}
	}
}

/**
 * Launches a controller that is not drawn on the screen in the usual button fashion, but still needs to be run.
 * @param {Object} _webWindowId
 * @param {Object} _website
 * @param {Object} _controller
 * @param {Object} _markedObjects
 * @param {Object} _sticky
 * @param {Object} _pageId
 * @param {Object} _dataObjectName
 */
function ControllerConfigurationStart(_webWindowId, _website, _controller, _markedObjects, _sticky, _pageId, _dataObjectName){
	var fakeButton = {};
	fakeButton.initialConfig = {};
	fakeButton.dataObjectName = _dataObjectName;
	fakeButton.initialConfig.website = _website;
	fakeButton.initialConfig.referringWebWindowId = _webWindowId;
	fakeButton.initialConfig.controllerConfiguration = _controller;
	fakeButton.initialConfig.pageId = _pageId;
	var p = ControllerStart(fakeButton, _markedObjects, _sticky);
	if (p) {
		return p;
    }
}

/** kerbe: IE has problems when it comes to json encoding when dealing with interactivity between separate windows (CLASSIC_WINDOW).
 * we have to hand build the structure
 */
function EncodeMarkedObjects(_markedObjects){
	var mo = {items:[]};
	
	if (_markedObjects){
		if (Ext.isIE){
			for (var i = 0; i < _markedObjects.items.length; i++) {
				mo.items[i] = {};				
				mo.items[i].id = _markedObjects.items[i].id;
				
				if (_markedObjects.items[i].totalCount) {
					mo.items[i].totalCount = _markedObjects.items[i].totalCount;
				}
				
				if (_markedObjects.items[i].filterSpecification) {
					mo.items[i].filterSpecification = _markedObjects.items[i].filterSpecification;
	            }
				
				mo.items[i].selections = {items:[]};
				
				for (var j = 0; j < _markedObjects.items[i].selections.length; j++) {
					mo.items[i].selections.items[j] = {};
					mo.items[i].selections.items[j].id = _markedObjects.items[i].selections.items[j].id;
					mo.items[i].selections.items[j].contentType = _markedObjects.items[i].selections.items[j].contentType;
					mo.items[i].selections.items[j].displayName = _markedObjects.items[i].selections.items[j].displayName;
					mo.items[i].selections.items[j].fileName = _markedObjects.items[i].selections.items[j].fileName;
					
					// tree selectors contain additional information that is needed to identify the node beyond the key
					// as a part of maunal construction of the marked objects, we need to consider that these attribs are 
					// furnished.
					mo.map = {};
										
					if (_markedObjects.items[i].id){
						mo.map[_markedObjects.items[i].id] = {};
						mo.map[_markedObjects.items[i].id].selections = {};
						mo.map[_markedObjects.items[i].id].selections.items = [];
						
						var item = {};
						if (_markedObjects.items[i].selections.items[j].id) {
							item.id = _markedObjects.items[i].selections.items[j].id;
						}
						
						if (_markedObjects.items[i].selections.items[j].nodeObjectFK) {
							item.nodeObjectFK = _markedObjects.items[i].selections.items[j].nodeObjectFK;
						}
						
						if (_markedObjects.items[i].selections.items[j].rootShareFK) {
							item.rootShareFK = _markedObjects.items[i].selections.items[j].rootShareFK;
						}
						
						if (_markedObjects.items[i].selections.items[j].rootTreePresFK) {
							item.rootTreePresFK = _markedObjects.items[i].selections.items[j].rootTreePresFK;
						}
						
						if (_markedObjects.items[i].selections.items[j].parentTreePresFK) {
							item.parentTreePresFK = _markedObjects.items[i].selections.items[j].parentTreePresFK;
						}
						
						if (_markedObjects.items[i].selections.items[j].parentNodeId) {
							item.parentNodeId = _markedObjects.items[i].selections.items[j].parentNodeId;
						}
						
						if (_markedObjects.items[i].selections.items[j].nodeName) {
							item.nodeName = _markedObjects.items[i].selections.items[j].nodeName;
			            }
			            
			            mo.map[_markedObjects.items[i].id].selections.items.push(item);

			            Ext.applyIf(mo.items[i].selections.items[j], item);
					}
				}
				
				mo.items[i].selectAll = _markedObjects.items[i].selectAll;
			}
		}
		else {
			mo = _markedObjects;
        }
	}
	
	return Ext.JSON.encode(mo);
}

/**
 * Continues an existing controller by calling into the same plugin that started the controller with a CONTINUE
 * behavior.  Allows wizard like postbacks, and updates from the server such as validation and error message
 * handling.  If the controller is done, this function will also close and cleanup the launched controller.
 * @param {Object} _buttonConfiguration
 */
function ControllerContinue(_buttonConfiguration, _markedObjects){
	if (_buttonConfiguration.controllerConfiguration && _buttonConfiguration.controllerConfiguration.PreController) {
		_buttonConfiguration.preactionType = _buttonConfiguration.controllerConfiguration.PreController.type;
	}
	
    var mo = _markedObjects || PageMgrFinder().getSelectionObjects(_buttonConfiguration.pageId, _buttonConfiguration.pageId);
	
	var xcode = EncodeMarkedObjects(mo);
	
	ShellFinder().LogToConsole('Encoded marked objects');
	ShellFinder().LogToConsole(xcode);
	
	var model = PageMgrFinder().getModel(_buttonConfiguration.pageId, _buttonConfiguration.pageId);	
	
	var params = {
		actionid: _buttonConfiguration.pageId,
		behavior: _buttonConfiguration.controllerConfiguration.behavior,
		dataIslandId: _buttonConfiguration.pageId,
		dataObjectName: _buttonConfiguration.dataObjectName,
		name: _buttonConfiguration.controllerConfiguration.name,
		actionArgument: _buttonConfiguration.controllerConfiguration.argument,
		dataIsland: Ext.JSON.encode(model),
		markedObjects: xcode,
		referringWebWindowId: _buttonConfiguration.referringWebWindowId,
		activecontrolfieldname: _buttonConfiguration.controllerConfiguration.activeControlFieldName,
		completedActionName: _buttonConfiguration.controllerConfiguration.completedControllerName,
		preactionType: _buttonConfiguration.preactionType,
		preactionAffirmativeResponse: _buttonConfiguration.preactionAffirmativeResponse,
		preactionInputValue: _buttonConfiguration.preactionInputValue,
		linkedSpecified: _buttonConfiguration.linkedSpecified,
		linked: _buttonConfiguration.linked,
		itemFuncListId: _buttonConfiguration.controllerConfiguration.itemFuncListId
	};
	
	if (_buttonConfiguration.controllerConfiguration.host === 'FORM') {
	    var formModel = PageMgrFinder().getModel(_buttonConfiguration.pageId, _buttonConfiguration.dataIslandId);
	    params.dataIsland = Ext.JSON.encode(formModel);
	    params.conduit = _buttonConfiguration.conduit;
	    params.plugin = _buttonConfiguration.plugin;
	    params.className = _buttonConfiguration.className;
	}
	
	ShellFinder().LogToConsole('Continuing Controller ' + params.name);
	ShellFinder().LogToConsole(params);    
	
    // If we have a window, then we need to reload everything inside of that particular window.  But there is also the posibility that this is a filter.  In that case, we want to reload the filter's panel instead of the window that doesn't exist.
	var window = Ext.WindowManager.get(_buttonConfiguration.pageId);
	var isClassicWindow = false;
	if (!window && Ext.getCmp(_buttonConfiguration.pageId)) {
		if (params.actionid.indexOf('_child') > -1 && (_buttonConfiguration.formReaderRoot == "records.flowchart" || _buttonConfiguration.dataObjectName == "flowchart" || _buttonConfiguration.formReaderRoot == "records.bookmarks" || _buttonConfiguration.dataObjectName == "bookmarks")) {
			// for editable flowchart, we need to fall through to another codepath...		
		}
		else {
			window = Ext.getCmp(_buttonConfiguration.pageId);
			if (window.xtype && !window.xtype === 'viewport') {
				window = null;
				// if its got an xtype, then its not a classic window.  This check was added after having added support for child actions off of
				// a procedure step.
			}
			else {
				// this is an classic window interaction controller.
				isClassicWindow = true;
			}
		}
	}
	
	if (window) {	
		// if the window was sticky then it had a mouseout event on it.  But if we're performing an action
		// then we need to remove that mouseout event so that we don't close the window when the user moves
		// their mouse out of the window
		if (!window.sticky) {
			window.el.un('mouseout', window.closeWindow, window);
		}
		
		// check to see if the forms in the window are all valid before posting back to the server
		var forms = Ext.ComponentQuery.query('form', window);;
		var valid = true;
		
		if (_buttonConfiguration.validate) {
			for (var i = 0; i < forms.length; i++) {
				if (!forms[i].getForm().isValid()) {
					valid = false;
                }
			}
		}
		
		if (valid) {
			if (!_buttonConfiguration.controllerConfiguration.suppressProcessIndicator) {
				// show loading of window stuff
				if (!isClassicWindow) {
					var w = Ext.WindowManager.get(_buttonConfiguration.pageId);
                    if (w && w.body) {
						w.body.mask(Ext.ux.LangMgr.ProcessingText.title, 'x-mask-loading');
                    }
				}
				else {
					Ext.get(document.body.id).mask(Ext.ux.LangMgr.ProcessingText.title, 'x-mask-loading');
				}
			}
			
			// make ajax request
			Ext.Ajax.request({
			    url: _buttonConfiguration.website,
			    params: params,
			    success: function(_response, _options) {
			        try {
			            var userData = PageMgrFinder().getUser();

			            var resObj = Ext.JSON.decode(_response.responseText);
			            if (resObj) {
			                HandleResponseHeader(resObj.header);
                        }

			            if (!resObj || !resObj.success) { //this is a really bad error, display generic error message to user from locale specific file			            
			                if (resObj) {
			                    DisplayResponseObject(resObj);
                            }
			                else {
			                    DisplayCommunicationError();
                            }

			                if (!isClassicWindow) {
			                    var w = Ext.WindowManager.get(_buttonConfiguration.pageId);
                                if (w && w.body) {
			                        w.body.unmask();
                                }
			                }
			                else {
			                    Ext.get(document.body.id).unmask();
                            }

			                return;
			            }                        

			            // if we get here, we got a good response
			            var win = null;
			            if (!isClassicWindow) {
			                win = Ext.WindowManager.get(resObj.data.pageId);
			            }
			            else {
			                win = Ext.getCmp(resObj.data.pageId);
			                
                            // if its still null, then try going to the opener
			                if (!win) {
			                    LogToConsole('Looking for parent window ');
			                    LogToConsole(resObj.data);

			                    win = opener.parent.Ext.getCmp(resObj.data.pageId);
			                    if (win) {
			                        LogToConsole('Got the parent window ');
			                        LogToConsole(win);
			                    }
			                    else {
			                        LogToConsole('no parent window found ');
                                }
			                }
			            }

			            // if there is a new control structure, unregister the stores for the old one because they are going to be replaced and we don't want them getting potentially new model that could cause reader exceptions
			            if (resObj && resObj.data.control) {
			                PageMgrFinder().unregisterStores(resObj.data.pageId, resObj.data.pageId);
			            }

			            // if the resObj has a new data structure, we need to reload the form data in the window
			            if (resObj && resObj.data && resObj.data.model) {
			                PageMgrFinder().setModel(resObj.data.pageId, resObj.data.pageId, resObj.data.model, true);
			                
                            if (resObj.data.dirty) {
			                    PageMgrFinder().manuallyDirtyIsland(resObj.data.pageId, resObj.data.pageId);
                            }
			                
                            // If there are any grids on the dialog that are pageable, then we need to reload all of those as well
			                // Only do this if the control is not getting rebuilt.
			                if (resObj && resObj.data && resObj.data.control) {
			                }
			                else {
			                    var grids = win.findByType('kgridbase');
			                    Ext.each(grids, function(grid) {
			                        if (grid.loadGridModel) {
			                            grid.loadGridModel(true, true, true);
			                        }
			                    });
			                }
			            }

			            // if the resObj has a new form structure, we need to remove the controls from the window, then load the controls into the window, doLayout, and then load the data into the window
			            if (resObj && resObj.data && resObj.data.control) {
			                while (win.items.length > 0) {
			                    var t = win.items.removeAt(0);
			                    if (Ext.isIE && t) {
			                        try {
			                            Ext.destroy(t);
			                        } catch (e) {
			                        }
			                    } else {
			                        Ext.destroy(t);
			                    }
			                }
			                
                            win.items.clear();
			                win.getLayout().activeItem = null;

			                if (userData && resObj && resObj.data && resObj.data.control) {
			                    if (resObj.data.control.pageId && !resObj.data.control.dataIslandId) {
			                        resObj.data.control.dataIslandId = resObj.data.control.pageId;
			                    }
			                    // initialize the control before inclusion
			                    resObj.data.control.currentItem = GetCurrentItem();
			                    resObj.data.control.editable = true;
			                }

                            // if this is an editable context screen, force all interaction controllers to stay at the top. also do not show any existing cancel controllers.
                            if (win.editableContextScreen && resObj.data.control && resObj.data.control.ControllerReference && resObj.data.control.ControllerReference.length > 0) {
                                Ext.each(resObj.data.control.ControllerReference, function(cr) {
                                    cr.controllerVAlign = 'TOP';
                                    
                                    if (cr.name === 'cancel') {
                                        resObj.data.control.ControllerReference.remove(cr);
                                    }
                                }, this);
                            }

			                win.add(resObj.data.control);
			                win.getLayout().setActiveItem(win.items.length - 1);
			                win.doLayout();
			            }

			            // if a windowTitle was provided, then override the Controller.windowTitle with it
			            if (resObj.data.windowTitle && !isClassicWindow) {
			                win.setTitle(resObj.data.windowTitle);
                        }

			            // if the response has indicated that the selector is dirty, then set that on the window.
			            // when the window closes, it will use this setting to determine if a reloadSelector call is needed.
			            if (resObj.data.selectorDirty && !isClassicWindow) {
			                win.selectorDirty = true;
                        }

			            // turn off loading stuff
			            if (win) {
			                if (!isClassicWindow) {
			                    win.body.unmask();
                            }
			                else {
			                    Ext.get(document.body.id).unmask();
                            }
			            }

			            // If we get some marked objects, then we need to correct the selections in the PageMgr so that everything is ok
			            if (resObj.data.markedObjects && resObj.data.pageId) {
			                PageMgrFinder().correctSelections(resObj.data.pageId, resObj.data.markedObjects);
			            }

			            // if the resObj is telling us that its all done (complete), then close the window.
			            if (resObj.success && resObj.data && resObj.data.complete) {
			                if (resObj.data.reloadApp && !resObj.data.reloadUser) {
			                    top.window.location = top.window.location.href;
			                    return;
			                }

			                // if the response indicates to clear node type actions explicitly, then do so
			                if (resObj.data.flushActionCache) {
			                    ShellFinder().Kaseya.web.managers.NodeTypeActions.unregisterIslands();
			                }

			                PageMgrFinder().manuallyCleanIsland(_buttonConfiguration.pageId, _buttonConfiguration.pageId);

			                // subtab grids loadGridModel wont fire the ajax request if the request newParams dont match the oldParams.  therefore, we need to flush those old params from the grids so that
			                // we can reread the data for those subtab grids that allowPaging.
			                var ctxScreen = ShellFinder().Ext.getCmp('contextScreen');
			                // if this is not a child action and we are about to close the window, flush the sub tab grids oldParams 
			                // so that they reload on action complete.  Only do this if we are still on the same item in the navigator
			                if (ctxScreen && (!_buttonConfiguration.parentid || !_buttonConfiguration.parentid.endsWith('_child'))) {
                                var grids = ctxScreen.find('xtype', 'kgridbase');
			                    for (var i = 0; i < grids.length; i++) {
			                        grids[i].oldParams = {};
                                }
			                }

			                var dialog = Ext.WindowManager.get(_buttonConfiguration.pageId);
			                if (!isClassicWindow) {
			                    try {			                        
			                        if (dialog && !dialog.editableContextScreen) {
			                            dialog.close();
			                        }
			                    }
			                    catch (_eex) {
			                    }
			                }
			                else {			                    
			                    // if we have receive a completeAlert, then show it now
			                    if (resObj.data.completeAlert && this.window.opener.showMessageBox) 
			                    {
			                        this.window.opener.showMessageBox(resObj.data.completeAlertTitle ? resObj.data.completeAlertTitle : ' ', resObj.data.completeAlert);
			                    }
		                            
                                this.window.close();
			                }

			                if (resObj.data.reloadCurrentScreen) {
			                    ReloadCurrentContext();
			                }
			                else {
			                    if (resObj.data.reloadUser) {
			                        if (userData && userData.currentLoadConfig && userData.currentLoadConfig.activeId && resObj && resObj.data && resObj.data.markedObjects && resObj.data.markedObjects.length > 0 && resObj.data.markedObjects[0].ids && resObj.data.markedObjects[0].ids.length > 0) {
			                            SetUserConfig({
			                                activeId: userData.currentLoadConfig.activeId,
			                                recordId: resObj.data.markedObjects[0].ids[0],
			                                activeAction: '',
			                                customParams: ''
			                            });
			                        }

			                        LoadUser({
			                            role: PageMgrFinder().getModel('user_store', 'user_store').currentRole,
			                            reloadApp: resObj.data.reloadApp ? true : false
			                        });

			                        if (resObj.data.reloadApp) {
			                            return;
                                    }
			                    }
			                    else {
			                        // reacquire the page number from the data response, since we may need to load a new page after completion of the action.
			                        if (ctxScreen && ctxScreen.Selector && ctxScreen.Selector.TreePanel && resObj.data.reloadSelector) {
			                            PageMgrFinder().getSelector(ctxScreen.pageId).reloadNode();
			                        }
			                        else if (resObj.data.reloadSelector) {
			                            if (dialog && !dialog.editableContextScreen) { // do not attempt to reload the selector if this is an editable context screen
			                                reloadSelector(resObj.data.reloadSelector, true);
			                            }
			                        }
			                    }

			                    // if we get a resObj.data.configuration object, then we had a parent action attached to this window that we just closed.
			                    // since we can't tell what the sub-window was doing to the parent, we'll just reload the window with the configuration
			                    // information passed in by the child

			                    if (resObj.data.configuration) {
			                        if (!isClassicWindow) {
			                            ControllerContinue(resObj.data.configuration);
                                    }
			                        else {
			                            // pass in the funcListId for the current item
			                            if (resObj.data.configuration.controllerConfiguration) {
			                                resObj.data.configuration.controllerConfiguration.itemFuncListId = _options.params.itemFuncListId;
                                        }

			                            ShellFinder().ControllerContinue(resObj.data.configuration);
			                        }
			                    }
			                }
			                
                            // if we have receive a completeAlert, then show it now
			                if (resObj.data.completeAlert) {
			                    Ext.Msg.show({
			                        title: resObj.data.completeAlertTitle || ' ',
			                        msg: resObj.data.completeAlert,
			                        minWidth: 200,
			                        maxWidth: 400,
			                        buttons: Ext.Msg.OK,
			                        icon: Ext.Msg.INFO
			                    });
			                }
			                
			                // clean up after editable context screen and navigate back to the navigation tree node
			                if (dialog && dialog.editableContextScreen) {		                                                    
                                dialog.pageMgr.pageDirty(false);	                   
                                
                                dialog.close();
                                
                                // remove the page from the page manager
                                if (dialog.id) {
                                    dialog.pageMgr.unregisterPage(dialog.id);
                                }                                  
                                
                                var cp = Ext.getCmp('CenterPanel');                                
                                var modTree = Ext.getCmp('modTree');
                                if (modTree) {
                                    var treeNode = modTree.selModel.selected.getAt(0);                                                                                                                                                    
                                    if (treeNode) {
                                        modTree.currentModule = modTree.store.getNodeById(treeNode.data.moduleId);
                                        modTree.fireEvent('beforeitemclick', modTree.getView(), treeNode);
                                        modTree.fireEvent('itemclick', modTree.getView(), treeNode);
                                    }
                                }
			                }
			            }
			        }
			        catch (ex) {
			            ResumeAllGridRefreshes();
			            
                        DisplayException(ex);
			            
                        if (!isClassicWindow && Ext.WindowManager.get(_buttonConfiguration.pageId) && Ext.WindowManager.get(_buttonConfiguration.pageId).body) {
			                Ext.WindowManager.get(_buttonConfiguration.pageId).body.unmask();
                        }
			            else {
			                Ext.get(document.body.id).unmask();
                        }
			        }
			    },
			    failure: function(_response, _options) {
			        try {
			            ResumeAllGridRefreshes();
			            var resObj = Ext.JSON.decode(_response.responseText);
			            DisplayResponseObject(resObj);
			        }
			        catch (_ex) {
			            DisplayException(_ex);
			        }
			    }
			});
		}
	}
	else if (_buttonConfiguration.formReaderRoot == "records.flowchart" || _buttonConfiguration.dataObjectName == "flowchart" || _buttonConfiguration.formReaderRoot == "records.bookmarks" || _buttonConfiguration.dataObjectName == "bookmarks") {
			// Ext.getCmp(_buttonConfiguration.pageId).ownerCt.body.mask(Ext.ux.LangMgr.ProcessingText.title, 'x-mask-loading');
			// make ajax request
			Ext.Ajax.request({
				url: _buttonConfiguration.website,
				params: params,
				success: function(_response, _options){
					try {
						var resObj = Ext.JSON.decode(_response.responseText);						
						if (resObj) {
							HandleResponseHeader(resObj.header);
                        }
						
						if (!resObj || !resObj.success) { //this is a really bad error, display generic error message to user from locale specific file						
							if (resObj) {
								DisplayResponseObject(resObj);
                            }
							else {
								DisplayCommunicationError();
                            }
							//  Ext.getCmp(_buttonConfiguration.pageId).body.unmask();
							return;
						}
						
						// if we get here, we got a good response
						var pnl = Ext.getCmp(_buttonConfiguration.pageId).ownerCt;
						// if there is a new control structure, unregister the stores for the old one because they are going to be replaced and we don't want them getting potentially new model that could cause reader exceptions
						if (resObj && resObj.data.control) {
							PageMgrFinder().unregisterStores(resObj.data.pageId, resObj.data.pageId);
						    //PageMgrFinder().removeSelectionObjects( resObj.data.pageId, resObj.data.pageId );
						}
						
						// if the resObj has a new data structure, we need to reload the form data in the window
						if (resObj && resObj.data && resObj.data.model) {
							PageMgrFinder().setModel(resObj.data.pageId, resObj.data.pageId, resObj.data.model, true);
							PageMgrFinder().manuallyDirtyIsland(resObj.data.pageId, resObj.data.pageId);
						}
						
						// if the resObj has a new form structure, we need to remove the controls from the window, then load the controls into the window, doLayout, and then load the data into the window
						if (resObj && resObj.data && resObj.data.control) {
							resObj.data.control.id = _buttonConfiguration.pageId;
							
							if (pnl) {
								for (var i = 0; i < pnl.items.length; i++) {
									Ext.destroy(pnl.items.items[i]);
								}
								pnl.items.clear();
								
								pnl.add(resObj.data.control);
								//pnl.getLayout().setActiveItem(pnl.items.length - 1);
								pnl.doLayout();
							}
						}
						
						// turn off loading stuff
						if (pnl) {
							pnl.body.unmask();
                        }
						
						// if the resObj is telling us that its all done (complete), then close the window.
						if (resObj.success && resObj.data && resObj.data.complete) {
							if (resObj.data.reloadApp && !resObj.data.reloadUser) {
								top.window.location = top.window.location.href;
								return;
							}
							
							PageMgrFinder().manuallyCleanIsland(_buttonConfiguration.pageId, _buttonConfiguration.pageId);
							
                            if (resObj.data.reloadCurrentScreen) {
								ReloadCurrentContext();
							}
							else {
								if (resObj.data.reloadSelector) {
									reloadSelector(resObj.data.reloadSelector);
                                }
								
								if (resObj.data.reloadUser) {
									LoadUser({
										role: PageMgrFinder().getModel('user_store', 'user_store').currentRole,
										reloadApp: resObj.data.reloadApp ? true : false
									});
									
									if (resObj.data.reloadApp) { 
										return;
                                    }
								}
								// if we get a resObj.data.configuration object, then we had a parent action attached to this window that we just closed.
								// since we can't tell what the sub-window was doing to the parent, we'll just reload the window with the configuration
								// information passed in by the child
								if (resObj.data.configuration) {
									ControllerContinue(resObj.data.configuration);
                                }
							}
						}
						// Now, if everything has gone well, then we need to reload the selector panel
						if (resObj.data.reloadSelector) {
							reloadSelector(resObj.data.reloadSelector);
                        }
					} 
					catch (ex) {
						DisplayException(ex);
					    // Ext.getCmp(_buttonConfiguration.pageId).body.unmask();
					}
				},
				failure: function(_response, _options){
					try {
						var resObj = Ext.JSON.decode(_response.responseText);
						DisplayResponseObject(resObj);
					} 
					catch (_ex) {
						DisplayException(_ex);
					}
				}
				
			});
		}
	else if (Ext.getCmp(_buttonConfiguration.pageId)) {
			// this is an classic window interaction controller.
			window = Ext.getCmp(_buttonConfiguration.pageId);
		}
	else {
		// we have raised an action command that isn't in a window.  As of the time of this writing, the only place that is legit is in the case of a filter.
		// show loading on the filter panel
		if (Ext.getCmp(_buttonConfiguration.pageId)) {
			Ext.getCmp(_buttonConfiguration.pageId).body.mask(Ext.ux.LangMgr.ProcessingText.title, 'x-mask-loading');
        }
				
		// make ajax request
		Ext.Ajax.request({
			url: _buttonConfiguration.website,
			params: params,
			success: function(_response, _options){
				try {
					var resObj = Ext.JSON.decode(_response.responseText);							
					if (resObj) {
						HandleResponseHeader(resObj.header);
                    }
							
					if (!resObj || !resObj.success) //this is a really bad error, display generic error message to user from locale specific file
					{
						if (resObj) {
							DisplayResponseObject(resObj);
                        }
						else {
							DisplayCommunicationError();
                        }

						if (Ext.getCmp(_buttonConfiguration.pageId)) {
							Ext.getCmp(_buttonConfiguration.pageId).body.unmask();
                        }

						return;
					}
							
					// if we get here, we got a good response
					var pnl = Ext.getCmp(_buttonConfiguration.pageId);
							
					// if there is a new control structure, unregister the stores for the old one because they are going to be replaced and we don't want them getting potentially new model that could cause reader exceptions
					if (resObj && resObj.data.control) {
						PageMgrFinder().unregisterStores(resObj.data.pageId, resObj.data.pageId);
						//PageMgrFinder().removeSelectionObjects( resObj.data.pageId, resObj.data.pageId );
					}
													
					// if the resObj has a new form structure, we need to remove the controls from the window, then load the controls into the window, doLayout, and then load the data into the window
					if (resObj && resObj.data && resObj.data.control) {
						pnl.add(resObj.data.control);
						pnl.getLayout().setActiveItem(pnl.items.length - 1);
						pnl.doLayout();
					}

					// if the resObj has a new data structure, we need to reload the form data in the window
					if (resObj && resObj.data && resObj.data.model) {
						PageMgrFinder().setModel(resObj.data.pageId, resObj.data.pageId, resObj.data.model, true);
						PageMgrFinder().manuallyDirtyIsland(resObj.data.pageId, resObj.data.pageId);
					}
							
					// turn off loading stuff
					if (pnl) {
						pnl.body.unmask();
                    }
							
					// if the resObj is telling us that its all done... then something went wrong
					if (resObj.success && resObj.data && resObj.data.complete) {
						AddDebugger();
					}
							
					// Now, if everything has gone well, then we need to reload the selector panel
					if (resObj.data.reloadSelector) {
						reloadSelector(resObj.data.reloadSelector);
					}
				} 
				catch (ex) {
					DisplayException(ex);
					Ext.getCmp(_buttonConfiguration.pageId).body.unmask();
				}
			},
			failure: function(_response, _options){
				try {
					var resObj = Ext.JSON.decode(_response.responseText);
					DisplayResponseObject(resObj);
				} 
				catch (_ex) {
					DisplayException(_ex);
				}
			}					
		});
	}
}

function showMessageBox(title, message, error) {
    Ext.Msg.show({
        title: title,
        msg: message,
        minWidth: 200,
        maxWidth: 400,
        buttons: Ext.Msg.OK,
        icon: error || Ext.Msg.INFO
    });
}

/**
 * Starts a controller with the provided selectionObjectId.  It will generate the marked object and start the controller
 * so that actions can be run, but not actions that should take into account the user's current selection.  For example,
 * if the user hasn't selected a record, but instead hovers over something that needs to launch a controller, the provided
 * selection id will be passed to the controller's handler instead of the records that are actually selected on the screen
 * so that the hover controller will correctly display the information for the hovered record.
 * @param {Object} _btnClicked
 * @param {Object} _selectionObjectId
 * @param {Object} _recordId
 * @param {Object} _sticky
 */
function PseudoControllerStart(_btnClicked, _selectionObjectId, _recordId, _sticky){
	if (this.callPseudoController) {
		var selectionObjects = new Ext.util.MixedCollection();
		var selectionObject = {
			id: _selectionObjectId,
			selections: new Ext.util.MixedCollection(),
			selectAll: false
		};

		selectionObject.selections.add({ id: _recordId });

		selectionObjects.add(selectionObject);
		ControllerCommandHandler(_btnClicked, selectionObjects, _sticky);
	}
}


// stub to deal with controller window close 
function OnControllerWindowClose(_pageId){
	//if we have a grid selector, make sure that all the same record(s) are selected again after the action
	//	var selector = PageMgrFinder().getSelector(_pageId);

	//determine if we have a grid or tree selector by checking for getSelections vs getSelectedNode
	//	if (selector && selector.getXType() == "treepanel") {
	//selector.show();
	//		}
}

// stub to deal with controller window start
function OnControllerWindowOpen(_pageId){
	//if we have a grid selector, make sure that all the same record(s) are selected again after the action
	//	var selector = PageMgrFinder().getSelector(_pageId);

	//determine if we have a grid or tree selector by checking for getSelections vs getSelectedNode
	//	if (selector && selector.getXType() == "treepanel") {
	//selector.hide();
	//		}
}

/**
 * On keyup handler that ensures when a key is pressed, that the data island is properly updated
 * with the correct information.  Usefull if the field you are constructing doesn't have a 'change'
 * listener on it and you still need to get the updated information out of it.
 * @param {Object} _field
 * @param {Object} _event
 */
function KeyUp(_field, _event){
	FieldChanged(_field, _field.getValue(), null);
}

/**
 * Handles when a field value has changed by updating the proper data island in the page that the field
 * is associated with.  If a controller is attached to the field, then we will run the controller after
 * the field's new value has been update in the data island to ensure that the backend gets the proper
 * information changes.
 * @param {Object} _field
 * @param {Object} _newVal
 * @param {Object} _oldVal
 * @param {Object} _force
 */
function FieldChanged(_field, _newVal, _oldVal, _force, _suppressController){
	try {
		var bUpdate = true;
		// if there is a grid reference attached to the field and it does not have force=true then it is the normal field change event. We do not
		// want to fire in this case because we want to grid 'afteredit' event to fire this event for the editable grid fields
		if (_field.gridReference && !_force) {
			bUpdate = false;
		}

		if (_field.initialConfig.formReaderRoot && _field.name && _field.pageId && _field.dataIslandId && bUpdate) {
			// KERBE: had to do this because if there are multiple editable grids the field.initialConfig.formReaderRoot for some reason assumes
			// that it has the same reader room as the initial rendered grid.
			var tmpReaderRoot = _field.initialConfig.formReaderRoot;
			
            // only change the value if we know the 'afteredit' event of the grid fired this
			if (_force && bUpdate) {
				tmpReaderRoot = _field.formReaderRoot;
			}

			if (PageMgrFinder().setModelItemValue(_field.pageId, _field.dataIslandId, tmpReaderRoot, _field.name, _newVal, _field.row, _field)) {
				// If there are other controls linked to this item in the data island, we need to update them as well
				var rootOwner = GetRootOwner(_field);
				if (rootOwner) {
					if (rootOwner.find) {
						// this only applies to form based controls.  if we are editing within a grid, the presumption is that there is no other control
						// bound to the same data that would need to be updated.
						var controls = rootOwner.find('name', _field.name);
						for (var i = 0; i < controls.length; i++) {
							if (controls[i].id != _field.id && controls[i].getRawValue && controls[i].getRawValue() !== _newVal && controls[i].initialConfig.formReaderRoot == _field.initialConfig.formReaderRoot) {
								controls[i].setValue(_newVal);
							}
						}
					}
				}
				
				// if this field is configured with a windowTitleTemplate, then we need to get the window
				// and then set the title with the replaced value from the field
				if (_field.windowTitleTemplate) {
					var window = _field.findParentByType('window');
					if (window) {
						var template = _field.windowTitleTemplate.replace(/{value}/g, _newVal);
						window.setTitle(template);
					}
				}
				
				// if there is a command on this particular control, then we need to call the controller handler
				if (_field.initialConfig.controllerConfiguration && !_suppressController) {
					ControllerClickHandler(_field);
				}
				
				// if the parent is an editable context screen, make sure we mark the page as dirty
				var win = _field.findParentByType('kcontrollerwindow');
				if (win && win.editableContextScreen) {
				   PageMgrFinder().pageDirty(true);
				}
			}
		}
	} 
	catch (_ex) {
		AddDebugger();
		DisplayException(_ex);
	}
}


/**
 * Handles when a MultiValue field has its value changed by updating the proper data island in the page that the field
 * is associated with.  If a controller is attached to the field, then we will run the controller after the field's
 * new value has been updated in the data island to ensure that the backend gets the proper information changes.
 * @param {Object} _field
 * @param {Object} _newVal
 * @param {Object} _oldVal
 */
function MultiValueFieldChanged(_field, _newVal, _oldVal, _suppressController){
	try {
		if (_field.initialConfig.formReaderRoot && _field.name && _field.pageId && _field.dataIslandId) {
			var model = PageMgrFinder().getModel(_field.pageId, _field.dataIslandId);
			if (model) {
				var formReaderRootParts = _field.initialConfig.formReaderRoot.split('.');
				var temp = '';
				var good = true;
				for (var i = 0; i < formReaderRootParts.length; i++) {
					temp += '.' + formReaderRootParts[i];
					if (!eval('model' + temp)) 
						good = false;
				}
				
				if (good) {
					var formReaderRootModel = eval('model.' + _field.formReaderRoot);
									
					if (formReaderRootModel && formReaderRootModel.data && formReaderRootModel.data[0] && Ext.isDefined(formReaderRootModel.data[0][_field.name])) {						
						formReaderRootModel.data[0][_field.name] = Ext.isArray(_newVal) ? _newVal : _newVal.split(',');
				    }
					/* 
					 * This was a good idea in theory, but we need to check to see if the new value is contained
					 * in the list of values from the multi-value control, not just if it is equal. controls[i].getRawValue() !== _newVal is wrong here
					 */
					/*
					 var rootOwner = GetRootOwner(_field);
					 if (rootOwner) {
					 var controls = rootOwner.find('name', _field.name);
					 for (var i = 0; i < controls.length; i++) {
					 if (controls[i].getRawValue() !== _newVal && controls[i].initialConfig.formReaderRoot == _field.initialConfig.formReaderRoot) {
					 controls[i].setValue(_newVal);
					 }
					 }
					 }
					 */
				}
			}
		}
		
		if (_field.initialConfig.controllerConfiguration && !_suppressController) {
			ControllerClickHandler(_field);
		}
		
		// if the parent is an editable context screen, make sure we mark the page as dirty
		var win = _field.findParentByType('kcontrollerwindow');
		if (win && win.editableContextScreen) {
		   PageMgrFinder().pageDirty(true);
		}		
	} 
	catch (_ex) {
		AddDebugger();
		DisplayException(_ex);
	}
}

/**
 * Cleans out the provided string of special characters and replaces them with the provided 'replaceWith' parameter
 * @param {Object} str
 * @param {Object} replaceWith
 * @return the sanitized string or null if nothing was provided.
 */
function SanitizeName(str, replaceWith){
	if (!str) {	
		return null;
    }
	
	//var re=/[(<>&?\]\[\\,\t|'\/\*\.#\+%:\s]/g;
	var re = /[,\#\%\'\"\:\*\?\<\>\|]/g;
	str = str.replace(re, replaceWith);
	
    return str;
}
/**
 * Loads a date configuration object from the server:
 * format - 0 to represent the display of 12-hour format 1 to represent the display of 24-hour format
 * browserOffset - the current offset of the browser from zulu time
 * serverOffset - the current offset of the server from zulu time
 * fixedOffset - the current offset to be used from zulu time
 * offsetPref - 0 to use browser offset, 1 to use server offset, 2 to use fixed offset
 * @param {Object} _config
 */
function loadDateConfiguration(_config){
	if (_config.format != null) {
		//Date format information
		if (_config.format == 0) {
			Date.DefaultDateFormat = 'd-M-y';
			Date.DefaultTimeFormat = 'g:i:s a';
			Date.DefaultDateTimeFormat = 'g:i:s a d-M-y';
		}
		else {
			Date.DefaultDateFormat = 'd-M-y';
			Date.DefaultTimeFormat = 'H:i:s';
			Date.DefaultDateTimeFormat = 'H:i:s d-M-y';
		}
		Date.DefaultAlternateFormats = 'c|g:i:s a d-M-y|d-M-y|g:i:s a|H:i:s|Y-m-d H:i:s|m/d/Y H:i:s|Y-m-d\\TH:i:s|m/d/Y|n/j/Y|n/j/y|m/j/y|n/d/y|m/j/Y|n/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d|Y-m-d|m/d/Y H:i:s A|n/j/Y H:i:s A|n/j/Y G:i:s A';
	}
	
	if (Ext.isNumber(_config.browserOffset)) {
		Date.browserOffset = _config.browserOffset;
    }
	else {
		Date.browserOffset = 0;
    }
	
	if (Ext.isNumber(_config.serverOffset)) {
		Date.serverOffset = _config.serverOffset;
    }
	else {
		Date.serverOffset = 0;
    }
	
	if (Ext.isNumber(_config.fixedOffset)) {
		Date.fixedOffset = _config.fixedOffset;
    }
	else {
		Date.fixedOffset = 0;
    }
	
	if (_config.offsetPref != null) {
		Date.offsetPref = _config.offsetPref;
		
        if (Date.offsetPref == 0) {
			Date.calculatedOffset = 0;
		}
		else if (Date.offsetPref == 1) {
			var diff = Math.abs(Date.serverOffset - Date.browserOffset);
			if (Date.serverOffset > Date.browserOffset) {
				diff = diff * -1;
            }

			Date.calculatedOffset = diff;
		}
		else if (Date.offsetPref == 2) {
			var diff = Math.abs((Date.serverOffset + Date.fixedOffset) - Date.browserOffset);
			if ((Date.serverOffset + Date.fixedOffset) > Date.browserOffset) {
				diff = diff * -1;
            }

			Date.calculatedOffset = diff;
		}
	}
}

/**
 * Parses a date given the provided default format and alternate formats.  This function will look for dates until the options are exhausted
 * @param {Object} _value
 * @param {Object} _format
 * @param {Object} _altFormats
 * @return the parsed date, or null
 */
function ParseDate(_value, _format, _altFormats){
	if (!_value || Ext.isDate(_value)) {
		return _value;
	}

	var v = Ext.Date.parse(_value, _format);
	var altFormatsArray;
	if (!v && _altFormats) {
		if (!altFormatsArray) {
			altFormatsArray = _altFormats.split("|");
		}

		for (var i = 0, len = altFormatsArray.length; i < len && !v; i++) {
			v = Ext.Date.parse(_value, altFormatsArray[i]);
		}
	}

	return v;
}

/**
 * Displays a generic communication failure message if there was a problem communicating with the server.
 */
function DisplayCommunicationError(){
	//AddDebugger();
    Ext.Error.raise({msg:Ext.ux.LangMgr.CommunicationError.message, title: Ext.ux.LangMgr.CommunicationError.title, display:true});
}

/**
 * Displays the response object retrieved from the server if it was not successfull.
 * The provided response object should have a title, msg, and icon configured to properly
 * display error messages
 * @param {Object} _responseObject
 */
function DisplayResponseObject(_responseObject){
	if (_responseObject) {
		if (_responseObject.stackTrace || _responseObject.dataPayload) {			
            Ext.Error.raise({
				title: (_responseObject.title || Ext.ux.LangMgr.CommunicationError.title),
				msg: (_responseObject.msg || ''),
				stackTrace: _responseObject.stackTrace,
				dataPayload: _responseObject.dataPayload,
                display:true
			});
		}
		else if (_responseObject.msg && _responseObject.msg.length > 0) {
            Ext.Error.raise({msg:_responseObject.msg, title: _responseObject.title || Ext.ux.LangMgr.CommunicationError.title,  display:true});
		} 
        else {
            Ext.Error.raise({msg:'A server error has occurred. Please see the debugger console for details.', title: 'Error'});
        }
	}
	else {
		DisplayCommunicationError();
	}
	
	var cp = Ext.getCmp('CenterPanel');
	if (cp && cp.el.isMasked()) {
	    cp.el.unmask();
	}
}

/**
 * Displays an exception to the user and if in debug mode, will allow a debugger to break on the exception for further investigation.
 * @param {Object} _ex
 */
function DisplayException(_ex){
	//AddDebugger();
	var msg = Ext.isObject(_ex) ? _ex.message : _ex;
	
    if (_ex.responseText) {
		Ext.Error.raise({
			title: Ext.ux.LangMgr.Exception.JavascriptExceptionText,
			msg: msg,
			dataPayload: _ex.responseText,
            display: true
		});
	}
	else {
		DisplayErrorMessage(Ext.ux.LangMgr.Exception.JavascriptExceptionText, msg);
	}			
}

/**
 * Displays an error message to the user given the provided title and message.
 * @param {Object} _title
 * @param {Object} _message
 */
function DisplayErrorMessage(_title, _message){
	Ext.Msg.show({
		title: _title,
		msg: _message,
		buttons: Ext.Msg.OK,
		icon: Ext.Msg.ERROR
	});
	
	var cp = Ext.getCmp('CenterPanel');
	if (cp && cp.el.isMasked()) {
	    cp.el.unmask();
	}	
}

function PageMgrFinder(_base){
	return ShellFinder(_base).Kaseya.web.managers.PageManager;
}

/**
 * Helper function to locate the vsapres shell.  The shell base contains the Ext library and the full complement of js function (such as Global.js) support.  
 * @param {Object} _base - this is an optional paremeter.  If nothing is passed, the current context will detect if an opener exists, else it will
 * assume top to begin its search for the page manager.  
 */
function ShellFinder(_base){
	 if (shellRef) {		
		 return shellRef;
     }
	
	var base = _base;
	if (!base) {
		base = this;
	}
	
	var hasParent = (base && base.parent && (base.location.href != base.parent.location.href));
	if (base && base.Kaseya && base.Kaseya.web && base.Kaseya.web.managers && base.Kaseya.web.managers.PageManager) {
		shellRef = base;
		return shellRef;
	}
	else if (hasParent) {
		return ShellFinder(base.parent);
	}
	else if (base && base.opener) {
		return ShellFinder(base.opener);
	}
	else {
		DisplayErrorMessage('Shell', 'The Shell could not be located.');
	}
}

/**
 * Determines whether the provided component is a form on the page, or a decendent of a form
 * @param {Object} _component
 * @param {Object} _container
 * @return true if the provided component is a form or descends from a form, false otherwise
 */
function FindAllForms(_component, _container){
	if (_component.isXType('form')) {		
		return true;
    }

	return false;
}

/**
 * Finds an object with the provided fieldName in an array of objects.
 * @param {Object} array
 * @param {Object} fieldName
 * @param {Object} fieldValue
 * @return the found object with the provided fieldName, or null if nothing was found.
 */
function FindIndexOfObjectInArray(array, fieldName, fieldValue){
	var index = -1;
	for (var i = 0; i < array.length; i++) {
		if (eval("array[i]." + fieldName) == fieldValue) {
			index = i;
			break;
		}
	}
	return index;
}

/**
 * Finds the first editable field on a form and tries to focus on the field control if possible
 * @param {Object} _cmp
 */
function FindFirstEditableFieldAndFocus(_cmp){
	var field = _cmp.items.findBy(FindByFieldType, _cmp);
	if (field && field.inputEl) {
	    field.focus();
	}
}

/**
 * Determines whether the provided component is an editable and visible field (or descendent of field) on the page
 * @param {Object} _component
 * @param {Object} _container
 * @return true if the component is a field or descends from a field and is editable and visible, false otherwise
 */
function FindByFieldType(_component, _container){
	try {
		if (_component.isXType('field') && !_component.disabled && !_component.readOnly && !_component.hidden && _component.isVisible()) {
			return true;
		}
			
		return false;
	} 
	catch (e) {
		return false;
	}
}

/**
 * Recursively searches for the top-most element that the passed control is a part of
 * @param {Object} _control
 */
function GetRootOwner(_control){
	if (_control.initialConfig && _control.initialConfig.isRoot) {
		return _control;
    }
	else if (_control.ownerCt) {
		return GetRootOwner(_control.ownerCt);
    }
	else {
		return _control;
    }
}

function getFunctionFrame(){
	return getFrameByName( "functionFrame" );
}

function getFrameByName(_name){
	for (var i = 0; i < this.frames.length; i++) {
		if (this.frames[i].name == _name) {		
			return this.frames[i];
        }
	}

	return null;
}

function getClickableString(_metaField, _record, _value){
	var clickableString = new Array();
	
	if (_metaField.HoverConfiguration && _metaField.HoverConfiguration.ControllerReference && _metaField.HoverConfiguration.ControllerReference.name) {
		clickableString.push(" onmouseover=\"var grid = Ext.getCmp( '", _record.store.gridId, "' ); if( grid ){ grid.callPseudoController = true; grid.callController( '", _metaField.HoverConfiguration.ControllerReference.name, "', '", _record.data.recordpk, "', ", (_metaField.HoverConfiguration.delay || 0), ", ", (_metaField.HoverConfiguration.sticky ? _metaField.HoverConfiguration.sticky.toLowerCase() : "true"), ");}\"");
		clickableString.push(" onmouseout=\"var grid = Ext.getCmp( '", _record.store.gridId, "' ); if( grid ){ grid.callPseudoController = false; }\"");
	}
	
	//shove ControllerReference into an array if it is an Object
	if (_metaField && _metaField.ClickConfiguration && _metaField.ClickConfiguration.ControllerReference && Ext.isObject(_metaField.ClickConfiguration.ControllerReference)) _metaField.ClickConfiguration.ControllerReference = [_metaField.ClickConfiguration.ControllerReference];
	
	if (_metaField && _metaField.ClickConfiguration && _metaField.ClickConfiguration.ControllerReference && _metaField.ClickConfiguration.ControllerReference.length > 0) {
		var tooltipFieldName = (_metaField.ClickConfiguration.tooltipFieldName ? _metaField.ClickConfiguration.tooltipFieldName.toLowerCase() : "");
		var tooltipText = new Array();
		if (tooltipFieldName) {
			tooltipText.push("data-qtip=\"", _record.data[tooltipFieldName], "\"");
        }
		else {
			tooltipText.push("data-qtip=\"", Ext.util.Format.htmlEncode(_value), "\"");
        }

		clickableString.push(tooltipText.join(''));
		
		var onClick = new Array();
		onClick.push(" style=\"cursor:pointer; cursor:hand;\"");
		
		var altConfig = new Array();
		var ctrlConfig = new Array();
		var shiftConfig = new Array();
		var defaultConfig = new Array();
		for (var i = 0; i < _metaField.ClickConfiguration.ControllerReference.length; i++) {
			if (_metaField.ClickConfiguration.ControllerReference[i].alternateModifier) {
				switch (_metaField.ClickConfiguration.ControllerReference[i].alternateModifier) {
					case 'ALT':
						altConfig.push(" if( Ext.EventObject.altKey ){grid.callController( '", _metaField.ClickConfiguration.ControllerReference[i].name, "', '", _record.data.recordpk, "', 0, true );return;}");
						break;
					case 'CTRL':
						ctrlConfig.push(" if( Ext.EventObject.ctrlKey ){grid.callController( '", _metaField.ClickConfiguration.ControllerReference[i].name, "', '", _record.data.recordpk, "', 0, true );return;}");
						break;
					case 'SHIFT':
						shiftConfig.push(" if( Ext.EventObject.shiftKey ){grid.callController( '", _metaField.ClickConfiguration.ControllerReference[i].name, "', '", _record.data.recordpk, "', 0, true );return;}");
						break;
				}
			}
			else {
				defaultConfig.push(" grid.callController( '", _metaField.ClickConfiguration.ControllerReference[i].name, "', '", _record.data.recordpk, "', 0, true );");
			}
		}
		onClick.push(" onclick=\"", "var grid = Ext.getCmp( '", _record.store.gridId, "' ); if( grid ){ grid.callPseudoController = true; ", altConfig.join(''), ctrlConfig.join(''), shiftConfig.join(''), defaultConfig.join(''), "};\" ");
		clickableString.push(onClick.join(''));
	}
	
	return clickableString.join('');
}

/**
 * Locates the default controller in a toolbar to run.  For example, a double-click
 * @param {Object} _toolbar
 * @return the default controller, or null if none is found
 */
function FindDefaultController(_toolbar){
	var res = null;
	if (_toolbar) {
		for (var i = 0; i < _toolbar.items.length; i++) {
			if (_toolbar.items.items[i].controllerConfiguration.isDefault) {
                res = _toolbar.items.items[i];
            }
		}
	}
	return res;
}

/**
 * Finds a Module by id in the provided collection.  If no module is found, null is returned.
 * @param {Object} _modules
 * @param {Object} _id
 * @return the found module, or null.
 */
function FindModule(_modules, _id){
	for (var i = 0; i < _modules.length; i++) {
		if (_modules[i].id == _id) {		
			return _modules[i];
        }
	}
	return null;
}


/**
 * For a given funcListId, this function searches until it finds the containing module for that specific funcListId.
 * If the funcListId doesnt exist, it returns the first module.
 * @param {Object} _modules
 * @param {Object} _funcListId
 * @param {Object} _defaultToFirstModule
 * @return the found module containing the funcListId, or the first module
 */
function FindModuleByFuncListId(_modules, _funcListId, _defaultToFirstModule){
	var mod;
	for (var i = 0; i < _modules.length; i++) {
		if (ModuleContainsFuncListId(_modules[i], _funcListId)) {
			return _modules[i];
		}
	}

	if (_defaultToFirstModule && _modules.length > 0) {
		return _modules[0];
    }
	else {
		return null;
    }
}

function FindSubItemByFuncListId(_modules, _funcListId){
    var item;
    for(var i = 0; i < _modules.length; i++){
        if(ModuleContainsFuncListId(_modules[i], _funcListId)){
            if(_modules[i].folders){
                for(var j = 0; j < _modules[i].folders.length; j++){
                    if(FolderContainsFuncListId(_modules[i].folders[j], _funcListId)){
                        if(_modules[i].folders[j].items){
                            for(var k = 0; k < _modules[i].folders[j].items.length; k++){
                                if(ItemContainsFuncListId(_modules[i].folders[j].items[k], _funcListId)){
                                    if(_modules[i].folders[j].items[k].subitems){
                                        for(var l = 0; l < _modules[i].folders[j].items[k].subitems,length; l++){
                                            if(SubItemContainsFuncListId(_modules[i].folders[j].items[k].subitems[l], _funcListId)){
                                                return _modules[i].folders[j].items[k].subitems[l];
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

function FindItemByFuncListId(_modules, _funcListId){
	var item;
	for (var i = 0; i < _modules.length; i++) {
		if (ModuleContainsFuncListId(_modules[i], _funcListId)) {
			if(_modules[i].folders){
				for (var j = 0; j < _modules[i].folders.length; j++) {
					if (FolderContainsFuncListId(_modules[i].folders[j], _funcListId)) {
						if(_modules[i].folders[j].items){
							for (var k = 0; k < _modules[i].folders[j].items.length; k++) {
								if (ItemContainsFuncListId(_modules[i].folders[j].items[k], _funcListId)) {									
									return _modules[i].folders[j].items[k];
								}
							}
						}
					}
				}
			}
		}
	}
	return null;
}

/**
 * Determines whether the provided module contains an item with the provided funcListId.
 * @param {Object} _module
 * @param {Object} _funcListId
 * @return true if a module is has a folder or item with the provided id, false otherwise.
 */
function ModuleContainsFuncListId(_module, _funcListId){
	if (_module.funcListID == _funcListId) {
		return true;
    }
	else {
		// check within the module
		if (_module.folders) {
			for (var i = 0; i < _module.folders.length; i++) {
				if (FolderContainsFuncListId(_module.folders[i], _funcListId)) {			
					return true;
                }
			}
		}
	}
	
	return false;
}

/**
 * Determines whether the provided folder contains an item with the provided funcListId.
 * @param {Object} _folder
 * @param {Object} _funcListId
 * @return true if the folder is the item or has an item with the provided id, false otherwise
 */
function FolderContainsFuncListId(_folder, _funcListId){
	if (_folder.funcListID == _funcListId) {
		return true;
    }
	else {
		// check within the folder
		if (_folder.folders) {
			for (var i = 0; i < _folder.folders.length; i++) {
				if (FolderContainsFuncListId(_folder.folders[i], _funcListId)) {
					return true;
                }
			}
		}

		// check within the item
		if (_folder.items) {
			for (var j = 0; j < _folder.items.length; j++) {
				if (ItemContainsFuncListId(_folder.items[j], _funcListId)) {
					return true;
                }
			}
		}
	}
	
	return false;
}


/**
 * Determines whether the provided item has the provided funcListId.
 * @param {Object} _item
 * @param {Object} _funcListId
 * @return true if the item is the item, false otherwise.
 */
function ItemContainsFuncListId(_item, _funcListId){
	if (_item.funcListID == _funcListId) {
		return true;
    }
	else {
		//check within item for controller references or subitems
		if (_item.controllerReferences) {
			for (var i = 0; i < _item.controllerReferences.length; i++) {
				if (_item.controllerReferences[i].funcListID == _funcListId) {
					return true;
                }
			}
		}
        
		// check within the item
		if (_item.subitems) {
			for (var j = 0; j < _item.subitems.length; j++) {
				if (SubItemContainsFuncListId(_item.subitems[j], _funcListId)) {
					return true;
                }
			}
		}

	}
	
	return false;
}

/**
 * Determines whether the provided subitem has the provided funcListId.
 * @param {Object} _subitem
 * @param {Object} _funcListId
 * @return true if the subitem is the subitem, false otherwise.
 */
function SubItemContainsFuncListId(_subitem, _funcListId){
	if (_subitem.funcListID == _funcListId) {
		return true;
    }
	else {
		//check within subitem for controller references
		if (_subitem.controllerReferences) {
			for (var i = 0; i < _subitem.controllerReferences.length; i++) {
				if (_subitem.controllerReferences[i].funcListID == _funcListId) {
					return true;
                }
			}
		}
	}
	
	return false;
}
/**
 * Finds the first item in the provided module.
 * @param {Object} _module
 * @return The first Item in the Module, or null if no item is found
 */
function FindFirstItemInModule(_module){
	if (_module && _module.folders) {
		for (var i = 0; i < _module.folders.length; i++) {
			if (_module.folders[i].items && _module.folders[i].items.length > 0) {
				return _module.folders[i].items[0];
			}
		}
	}

	return null;
}

/**
 * If we get a response from the server that the user is already logged off,
 * then we need to redirect to the mainLogon.asp page 
 */
function LoggedOff(){
	top.location = logoffURL || "/mainLogon.asp?logout=" + String(Math.random());
}

/**
 * Shows the Navigation Panel on the left side of the screen
 */
function ShowNavigation(){
	var nav = Ext.getCmp('Navigator');
	if (nav) {
        nav.expand();
    }
}

/**
 * Collapses the Navigation Panel on the left side of the screen, providing maximum screen real-estate for the selected screen.
 */
function HideNavigation(){
	var nav = Ext.getCmp('Navigator');
	if (nav) {
        nav.collapse();
    }
}

/**
 * Helper function that will disable bookmark functionality in the framework
 */
function disableBookmarks(){
	var navigator = Ext.getCmp('Navigator');
    var navToolbar = Ext.getCmp('NavToolBar');

    if (navigator && navToolbar) {
		var navToolbarWidth = navigator.width;
		var minNavigatorWidth = navigator.minNavigatorWidth;
		var navigatorButtonWidth = navigator.navigatorButtonWidth;
		
		if (navToolbar.showBookmarkButton.hidden) {
			navToolbar.showBookmarkButton.hide();
			navToolbarWidth = navToolbarWidth - navigatorButtonWidth;
		}

		if (navToolbar.addBookmarkButton.hidden) {
			navToolbar.addBookmarkButton.hide();
			navToolbarWidth = navToolbarWidth - navigatorButtonWidth;
		}
		
		navigator.setWidth((navToolbarWidth < minNavigatorWidth ? minNavigatorWidth : navToolbarWidth));
		Ext.getCmp('PageShellViewPort').doLayout();
	}
}

/**
 * Helper function that will enable bookmark functionality in the framework
 */
function enableBookmarks(){
	var navigator = Ext.getCmp('Navigator');
    var navToolbar = Ext.getCmp('NavToolBar');	

    if (navigator && navToolbar) {
		var navToolbarWidth = navigator.width;
		var minNavigatorWidth = navigator.minNavigatorWidth;
		var navigatorButtonWidth = navigator.navigatorButtonWidth;
				
		navToolbar.showBookmarkButton.show();
		navToolbar.addBookmarkButton.show();
		
		navigator.setWidth((navToolbarWidth < minNavigatorWidth ? minNavigatorWidth : navToolbarWidth));
		Ext.getCmp('PageShellViewPort').doLayout();
	}
}

 /**
   * Navigates to the correct navigation item based on the provided parameters
   * 
   * @access public
   * @param a load configuration contains three params
   * activeId: the funcListId within the navigation panel to select.  could be a module, folder or item
   * recordId: if provided, after having loaded the funcListID item, this record will be selected in the selector panel.
   * activeAction: the controller name to raise.  for instance, to edit a specific record, a recordId is provided and the controller name for edit is furnished, resulting in the controller being raised.
   * filterValue: the current filter to draw the screen with
   * customParams: array of name value pair objects [{param1:'summaryInformation'}, {param2:'detailInformation'}]
   * { activeId: '10014', recordId: '1009873', activeAction:'edit' }
   * _windowId: give a windowId to open in a separate window with this id.
   */
function NavigateToWindow(_loadConfiguration, _windowId){
	var windowId = _windowId;
	if (!windowId) {
        windowId = GenerateUniqueActionId();
    }

	var user = PageMgrFinder().getUser();
	var path = '/home.asp';
	
	path = path + '?' + Ext.Object.toQueryString(_loadConfiguration);
	// if we have custom params add those on
	if (_loadConfiguration && _loadConfiguration.customParams) {
		path = path + '&' + Ext.Object.toQueryString(_loadConfiguration.customParams);
	}

	OpenKaseyaWindow(this, path, user.webWindowId, true, null, windowId);
}

 /**
   * Navigates to the correct navigation item based on the provided parameters
   * 
   * @access public
   * @param a load configuration contains three params
   * activeId: the funcListId within the navigation panel to select.  could be a module, folder or item
   * recordId: if provided, after having loaded the funcListID item, this record will be selected in the selector panel.
   * activeAction: the controller name to raise.  for instance, to edit a specific record, a recordId is provided and the controller name for edit is furnished, resulting in the controller being raised.
   * filterValue: the current filter to draw the screen with
   * customParams: array of name value pair objects [{param1:'summaryInformation'}, {param2:'detailInformation'}]
   * { activeId: '10014', recordId: '1009873', activeAction:'edit' }
   * http://localhost/home.asp?firstIn=true&activeId=10014&activeAction=edit&recordId=Kaseya
   */
function NavigateTo(_loadConfiguration) {
	// if the page is dirty, then we want to check with the user before doing something stupid	
	if (PageMgrFinder().pageDirty()) {
		// prompt the user to make sure that they are really wanting to close without saving changes
		Ext.Msg.on({
			show: function() {
				this.msgButtons[3].focus();
			},
			single: true,
			delay: 50
		});
		
		Ext.Msg.show({
			title: Ext.ux.LangMgr.NavigateAway.title,
			msg: Ext.ux.LangMgr.CloseWithoutSaving.message,
			// TODO4
			/*buttons: {
				yes: Ext.ux.LangMgr.CloseWithoutSaving.noSave,
				cancel: true
			},*/
			buttons: Ext.Msg.OKCANCEL,
			icon: Ext.Msg.QUESTION,
			scope: _loadConfiguration,
			fn: NavigateAwayToHandler
		});
		
        return false;
	}
	
	// apply a check to verify that the case is correct
	if (_loadConfiguration.activeid) {
		Ext.Error.raise({title: Ext.ux.LangMgr.Exception.JavascriptExceptionText, msg: 'NavigateTo error.  The case is incorrect.  activeId is supported, but activeid was provided.'});
	}

	if (_loadConfiguration.recordid) {
		Ext.Error.raise({title: Ext.ux.LangMgr.Exception.JavascriptExceptionText, msg: 'NavigateTo error.  The case is incorrect.  recordId is supported, but recordid was provided.'});;
	}

	if (_loadConfiguration.activeaction) {
		Ext.Error.raise({title: Ext.ux.LangMgr.Exception.JavascriptExceptionText, msg: 'NavigateTo error.  The case is incorrect.  activeAction is supported, but activeaction was provided.'});
	}

	if (_loadConfiguration.filtervalue) {
		Ext.Error.raise({title: Ext.ux.LangMgr.Exception.JavascriptExceptionText, msg: 'NavigateTo error.  The case is incorrect.  filterValue is supported, but filtervalue was provided.'});
	}

	if (_loadConfiguration.customparams) {
		Ext.Error.raise({title: Ext.ux.LangMgr.Exception.JavascriptExceptionText, msg: 'NavigateTo error.  The case is incorrect.  customParams is supported, but customparams was provided.'});
	}
	
	var user = PageMgrFinder().getUser();
	
	var loadConfig = Ext.JSON.encode(_loadConfiguration);
	
	Ext.apply(user.currentLoadConfig, Ext.JSON.decode(loadConfig));
	
	for (var x = 0; x < PageMgrFinder().items.length; x++) {
		var id = PageMgrFinder().items[x].id;
        if (id && id != 'user_store') {
			PageMgrFinder().unregisterPage(id);
			x--;
		}
		
        // flush out any cached node action collections.
		// this will limit reuse of node type actions in lieu of conserving memory in the browser.
		Kaseya.web.managers.NodeTypeActions.unregisterIslands();
	}
	
	var cs = Ext.getCmp('contextScreen');
    if (cs) {
		Ext.destroy(cs);
	}

    Ext.iterate(Ext.WindowManager.list, function(windowId) {
        var window = Ext.WindowManager.get(windowId);
        if (window && window.editableContextScreen) {
            window.close();
            Ext.destroy(window);
        }
    }, this); 
	
	LoadConfig(user);
    
    var modTree = Ext.getCmp('modTree');
    if (modTree) {
        var activeNode = modTree.store.getNodeById(user.currentLoadConfig.activeId);
        if (activeNode) {
            var cp = Ext.getCmp('CenterPanel');
            if (cp) {          
                modTree.currentModule = modTree.store.getNodeById(activeNode.data.moduleId);
                modTree.lastNode = activeNode;                
                modTree.cleanup();

                if(!_loadConfiguration.dataSetNavigation) { // don't monkey with the tree if we're switching between data sets.
                    if (modTree.basicMode) {
                        modTree.resetToBasic();
                    } else {
                        modTree.resetToAdvanced();
                    }
                }

                modTree.currentModule = modTree.store.getNodeById(activeNode.data.moduleId);
                modTree.fireEvent('beforeitemclick', modTree.getView(), activeNode);
                modTree.fireEvent('itemclick', modTree.getView(), activeNode);
            }
        }
    }
}				   			   					   				   

/**
 * Reloads the current user.  This is useful if we need to update the username from the preferences page
 */
function ReloadUser(_params){
	var params = { role: PageMgrFinder().getModel('user_store', 'user_store').currentRole };
	
    Ext.applyIf(params, _params);
	
    LoadUser(params);
}

/**
 * Reloads the current user configuration
 */
function ReloadCurrentContext(){
	var user = PageMgrFinder().getUser();
	LoadConfig(user);
}

/**
 * Reloads the Selection Panel Data Stores for the provided page, island, and data.
 * If controls are on the selection panel, then the data will be pushed into the
 * controls in the selection panel automatically.
 * @param {Object} _pageId
 * @param {Object} _islandId
 * @param {Object} _data
 */
function ReloadSelectionPanelDataStores(_pageId, _islandId, _data){
	var page = PageMgrFinder().get(_pageId, _islandId);
	for (var i = 0; i < page.stores.length; i++) {
		page.stores[i].loadData(_data);
	}
}

/**
 * Loads the current load configuration in _userData by selecting the proper item in the navigation control.
 * If access is not allowed to the provided funcListId, then a NoAccessError message is displayed to the user.
 * @param {Object} _userData
 */
function LoadConfig(_userData){	
    if (_userData) {
		// funcListIds to use in case we do not find any matches
        var inbox = '16810';
		var chgLogon = '1001';

		// verify user access
		if (_userData && _userData.currentLoadConfig && _userData.currentLoadConfig.activeId && _userData.currentLoadConfig.activeId.length > 0) {
            if (verifyUserAccess(_userData)) {
				var m = FindModuleByFuncListId(_userData.applications[0].modules, _userData.currentLoadConfig.activeId, true);
				// check if the module is visible if not, then grab the first module
				if (!m.visible) {
					var i = FindItemByFuncListId(_userData.applications[0].modules, _userData.currentLoadConfig.activeId);
					if (i && i.contextName && (i.contextName.indexOf('url=')==0 || i.contextName.indexOf('kurl=')==0)){
						var ivurl = '';
						if (i.contextName.indexOf('url=')==0) {
							ivurl = i.contextName.replace('url=', '');
                        }
						else {
							ivurl = i.contextName.replace('kurl=', '');
                        }

						if (_userData.currentLoadConfig.customParams){
							for(var m = 0; m < _userData.currentLoadConfig.customParams.length; m++) {
								for(var parname in _userData.currentLoadConfig.customParams[m]) {							
									ivurl += (ivurl.indexOf('?')>-1?'&':'?') + parname + '=' +  _userData.currentLoadConfig.customParams[m][parname];
								}
							}
						}
						
						InsertScreen({
							xtype: 'kurlscreen',
							id: 'contextScreen',
							url: ivurl
						}, Ext.getCmp('CenterPanel'));
					}
					else
					{
						m = FindModuleByFuncListId(_userData.applications[0].modules, inbox, false);
						_userData.currentLoadConfig.activeId = inbox;

						if (!m) {
							m = FindModuleByFuncListId(_userData.applications[0].modules, chgLogon, false);
							_userData.currentLoadConfig.activeId = chgLogon;
						}
					}
				}
				
                if (m) {
					setTimeout(function() {
                        var modPanel = Ext.getCmp('modTree');
					    if (modPanel) {						                        
                            var treeNode = modPanel.store.getNodeById(_userData.currentLoadConfig.activeId);
                            if (treeNode) {
                                modPanel.currentModule = modPanel.store.getNodeById(treeNode.data.moduleId);
                                modPanel.fireEvent('beforeitemclick', modPanel.getView(), treeNode);
                                modPanel.fireEvent('itemclick', modPanel.getView(), treeNode);
                            }
					    }
                    }, 10); // introduce a short delay to make sure the nav tree is available on the first page load
				}
			}
			else {
				// instead of raising an error, just redirect to the default landing page because its a permissions
				// issue and not an actual error.  We don't want support calls for errors that are just mis-configurations.
				var m = FindModuleByFuncListId(_userData.applications[0].modules, inbox, false);
				_userData.currentLoadConfig.activeId = inbox;
				
                if (!m) {
					m = FindModuleByFuncListId(_userData.applications[0].modules, chgLogon, false);
					_userData.currentLoadConfig.activeId = chgLogon;
				}

				if (m) {
					var modPanel = Ext.getCmp('modTree');
					if (modPanel) {						                        
                        var treeNode = modPanel.store.getNodeById(_userData.currentLoadConfig.activeId);
                        if (treeNode) {
                            modPanel.currentModule = modPanel.store.getNodeById(treeNode.data.moduleId);
                            modPanel.fireEvent('beforeitemclick', modPanel.getView(), treeNode);
                            modPanel.fireEvent('itemclick', modPanel.getView(), treeNode);
                        }
					}
				}

				// raise message indicating that access is not allowed to this navigation target.
				//DisplayErrorMessage(Ext.ux.LangMgr.NoAccessError.title, Ext.ux.LangMgr.NoAccessError.message);
			}
		}
	}
}

/**
 * Handles all ajax response headers from the web server.
 * Logs user off if session has expired.
 * Notifies user if session is about to expire.
 * Annoys user if they have unread messages.
 * @param {Object} _header
 */
function HandleResponseHeader(_header){
	if (_header) {	
        var notificationBar = Ext.getCmp('NotificationBar');
        var bannerBar = Ext.getCmp('BannerBar');
		
		// check for logoff and session warning and expiration
		if (_header.logoff) {
			LoggedOff();
			return false;
		}
		else {
			if (_header.sessionExpiration && _header.sessionExpirationStyle && bannerBar) {
				bannerBar.setWelcomeText(_header.sessionExpiration, _header.sessionExpirationStyle);
			}
			else if (bannerBar) {
				bannerBar.setWelcomeName();
			}
		}
		
		// process messages
		if (_header.unreadMessages && notificationBar) {
			notificationBar.setUnreadMessagesText(_header.unreadMessages);
		}
		else if (notificationBar) {
		    notificationBar.resetUnreadMessagesText();
		}
		
		// process server status
		if (_header.serverStatus && notificationBar) {
			notificationBar.setServerStatusText(_header.serverStatus, _header.serverStatusStyle);
		}
		else if (notificationBar) {
		    notificationBar.resetServerStatusText();
		}
		
		// process chat window information
		if ( _header.chatWindow ) {
			OpenChatWindow( _header.chatWindow.adChatId, _header.chatWindow.chatId, _header.chatWindow.snd, _header.chatWindow.autoClose );
		}
		
		//todo: process all the other stuff
		return true;
	}
	else {
		return true;
    }
}

/**
 * Helper function that will handle the successful ajax response from the web server after a call to GetScreen was made.
 * Builds the control provided by the server onto the screen, and destroys any existing information on the screen that
 * needs to be cleaned up to avoid any memory leaks.
 * @param {Object} _response
 * @param {Object} _options
 */
function OnGetScreenSuccess(_response, _options){
	try {
		// load in the model
		var resObj = Ext.JSON.decode(_response.responseText);
		if (resObj && HandleResponseHeader(resObj.header) && resObj.success) {
			InsertScreen(resObj.data, this);
		}
		else {
			DisplayResponseObject(resObj);
		}

		if (resObj) {
			if (resObj.data) {
                delete resObj.data; 
            }
			delete resObj;
		}
	} 
	catch (_ex) {
		for (var i = 0; i < this.items.length; i++) {
			Ext.destroy(this.items.items[i]);
		}
		this.items.clear();
		DisplayException(_ex);
	}
}

function InsertScreen(_screen, _scope){
	try {
		SetUserConfig({
			resetFilter: false
		});

		Ext.ComponentMgr.unregister(_screen);
		
        if (_scope.el) {
			for (var i = 0; i < _scope.items.length; i++) {
				try {
					Ext.destroy(_scope.items.items[i]);
				} 
				catch (e) {
				
				}
			}
			_scope.items.clear();
		}

		_scope.add(_screen);
		_scope.getLayout().setActiveItem(_scope.items.length - 1);
		_scope.doLayout();
	} 
	catch (_ex) {		
		if (_scope.el) {
		    for (var i = 0; i < _scope.items.length; i++) {
			    Ext.destroy(_scope.items.items[i]);
		    }
		    
		    _scope.items.clear();
		}
		
		DisplayException(_ex);
	}
}

/**
  * Helper function that will handle the successful ajax response from the web server after a call to GetScreen was made.
  * Builds the control provided by the server onto the screen, and destroys any existing information on the screen that
  * needs to be cleaned up to avoid any memory leaks.
  * @param {Object} e
  * @param {Object} _response
  */
 function OnGetScreenSuccessPort(e, _response){
	if (_response && _response.status) {
		try {
			//load in the model
			var resObj = Ext.JSON.decode(_response.result);
			if (resObj && HandleResponseHeader(resObj.header) && resObj.success) {
				var cp = Ext.getCmp('CenterPanel');
				
				SetUserConfig({ resetFilter: false });
				
				Ext.ComponentMgr.unregister(resObj.data);
				
				if (cp.el) {
					for (var i = 0; i < cp.items.length; i++) {
						try {
							Ext.destroy(cp.items.items[i]);
						} 
						catch (e) {
						
						}
					}
					
                    cp.items.clear();
				}
				
				resObj.data.currentItem = this;
				
				if (cp && cp.el && cp.el.isMasked()) {
				    cp.el.unmask();
				}
												
				cp.add(resObj.data);
			    cp.getLayout().setActiveItem(cp.items.length - 1);
			    cp.doLayout();
			}
			else {
				AddDebugger();
				DisplayResponseObject(resObj);
			}
			
			if (resObj) {
				if (resObj.data) delete resObj.data;
				delete resObj;
			}
		} 
		catch (_ex) {
			var cp = Ext.getCmp('CenterPanel');
			for (var i = 0; i < cp.items.length; i++) {
				Ext.destroy(cp.items.items[i]);
			}
			cp.items.clear();
			DisplayException(_ex);
		}
	}
	else {
		DisplayException(_response.message);
	}
}

function GetCurrentItem() {
	var user = PageMgrFinder().getUser();
	if (user && user.currentLoadConfig && user.currentLoadConfig.activeId){
		return FindItemByFuncListId(user.applications[0].modules, user.currentLoadConfig.activeId);
	}

	return null;
}	
 
function SetDimension(_name, _value) {
	var user = PageMgrFinder().getUser();
	var dimensionArray = user.currentLoadConfig.dimensions;
	var contains = false;
	for (var i = 0; i < dimensionArray.length; i++) {
		if (dimensionArray[i].name == _name) {
			dimensionArray[i].value = _value;
			contains = true;
		}
	}

	if (!contains) {
		dimensionArray.push({
			name: _name,
			value: _value
		});
	}
	
    return dimensionArray;
}

/**
 * Sets the User Configuration with the configuration provided and adds information to the History Manager
 * if the new configuration is significantly different from the existing configuration.
 * @param {Object} _loadConfiguration
 */
function SetUserConfig(_loadConfiguration) {
	var user = PageMgrFinder().getUser();
	
	try {
		var activeId = user.currentLoadConfig.activeId;
	} 
	catch (e) {
		user.currentLoadConfig = {};
	}
	
	// only if the activeId changes can we do this.  Use the apply in case a partial load config is provided, such as the reset button on the filter bar
	if (user.currentLoadConfig.activeId != _loadConfiguration.activeId) {
		Ext.apply(user.currentLoadConfig, _loadConfiguration, {
			activeId: user.currentLoadConfig.activeId || '',
			activeAction: user.currentLoadConfig.activeAction || '',
			recordId: user.currentLoadConfig.recordId || '',
			filterName: user.currentLoadConfig.filterName || '',
			dimensions: user.currentLoadConfig.dimensions || [],
			customParams: user.currentLoadConfig.customParams || '',
			resetFilter: user.currentLoadConfig.resetFilter || false
		});
		
	}
	else {
		user.currentLoadConfig.recordId = _loadConfiguration.recordId;
		user.currentLoadConfig.activeAction = _loadConfiguration.activeAction;
		user.currentLoadConfig.customParams = _loadConfiguration.customParams;
		user.currentLoadConfig.filterName = _loadConfiguration.filterName;
		user.currentLoadConfig.dimensions = _loadConfiguration.dimensions;
		user.currentLoadConfig.resetFilter = _loadConfiguration.resetFilter;
	}
	
    PageMgrFinder().setLoadConfig('user_store', 'user_store', user.currentLoadConfig);
	
	//Setup the history information.  only add if the active id has changed and there is no activeAction	
	if (_loadConfiguration && _loadConfiguration.activeId != null && _loadConfiguration.activeAction == null || _loadConfiguration.activeAction == '') {
        Ext.History.add("navigation" + tokenDelimiter + _loadConfiguration.activeId);
    }
}


function CheckHtml(frame){
	var frameHtml;	
	if (frame && frame.contentDocument && frame.contentDocument.documentElement) {
		frameHtml = frame.contentDocument.documentElement.innerHTML;
	}
	
	var valid = false;
	if (frameHtml) {
		// checkHtml is valid
		if ((frameHtml.startsWith('<head') || frameHtml.startsWith('<HEAD') || frameHtml.startsWith('<Head')) && (frameHtml.endsWith('</body>') || frameHtml.endsWith('</BODY>') || frameHtml.endsWith('</Body>'))) {
            valid = true;
        }
	}
	else {
		// This case occurrs in IE7 only where the contentDocument is unavailable.
		// In this case we need to check as much of the document as possible for validity.
		frameHtml = frame.contentWindow.document.body.innerHTML;
		frameHtml = frameHtml.trim();
		if ((frameHtml.startsWith('<form') || frameHtml.startsWith('<FORM') || frameHtml.startsWith('<Form')) && (frameHtml.endsWith('</script>') || frameHtml.endsWith('</SCRIPT>') || frameHtml.endsWith('</Script>'))) {
            valid = true;
        }
	}
	
	// If the frame is not valid, reload it
	if (!valid) {
		var src = frame.src;
		var srcs = src.split('?');
		src = srcs[0];
		var newSrc = src + '?' +
		Ext.Object.toQueryString({
			random: Math.random()
		});
		frame.src = newSrc;
	}
}

/**
 * Sets the current help context into the User Configuration to be accessed if the user clicks on a help link
 * @param {Object} _helpContext
 */
function SetHelpContext(_helpContext){
	var user = PageMgrFinder().getUser();
	
	Ext.apply(user.currentHelpContext, _helpContext);
	
    PageMgrFinder().setHelpContext('user_store', 'user_store', user.currentHelpContext);
}

/**
 * Gets the current Web Window Id
 * @return the current WebWindowId
 */
function GetWebWindowId(){
	var user = PageMgrFinder().getUser();
	return user.webWindowId;
}

/**
 * Inserts a dynamically provided css link into the header of the page.
 * @param {Object} _head
 * @param {Object} _linkRef
 */
function InsertCssLink(_head, _linkRef){
	var headID = document.getElementsByTagName("head")[0];
	var cssNode = document.createElement('link');
	cssNode.type = 'text/css';
	cssNode.rel = 'stylesheet';
	cssNode.href = _linkRef;
	cssNode.media = 'screen';
	_head.appendChild(cssNode);
}

/**
 * Returns the value of the provided param name in the provided url
 * @param {Object} _url
 * @param {Object} _paramName
 * @return the value of the provided param name, or null if no param name is found
 */
function GetUrlParam(_url, _paramName){
	var result;
	var url = _url;
	var urlParams;
	var getParams = url.split("?");
	if (getParams.length > 2) {
		var tmpUrl = getParams[0];
		for (var i = 1; i < getParams.length; i++) {
			if (i == 1) {
				tmpUrl = tmpUrl + '?' + getParams[i];
            }
			else {
				tmpUrl = tmpUrl + '&' + getParams[i];
            }
		}

		getParams = tmpUrl.split("?");
	}
	
	// if there were params, decode them
	if (getParams.length == 2) {
		urlParams = Ext.Object.fromQueryString(getParams[1]);
		result = urlParams[_paramName];
	}
	
	return result;
}

/**
 * Adds a parameter to a url.
 * @param {Object} _url
 * @param {Object} _paramName
 * @param {Object} _paramValue
 * @return the correctly formatted url with the parameter name and value appended
 */
function AddUrlParam(_url, _paramName, _paramValue){
	var url = _url;
	var urlParams;
	var getParams = url.split("?");
	if (getParams.length > 2) {
		var tmpUrl = getParams[0];
		for (var i = 1; i < getParams.length; i++) {
			if (i == 1) 
				tmpUrl = tmpUrl + '?' + getParams[i];
			else 
				tmpUrl = tmpUrl + '&' + getParams[i];
		}
		getParams = tmpUrl.split("?");
	}
	
	// if there were params, decode them
	if (getParams.length == 2) {
		urlParams = Ext.Object.fromQueryString(getParams[1]);
		urlParams[_paramName] = _paramValue;
	}
	else {
		urlParams = {};
		urlParams[_paramName] = _paramValue;
	}

	return getParams[0] + '?' + Ext.Object.toQueryString(urlParams);	
}

/**
 * Open another Kaseya Window and notify the web server that another window is being created so that it can properly link/separate
 * the windows from each other.
 * @param {Object} _extRoot
 * @param {Object} _url
 * @param {Object} _referringWebWindowId
 * @param {Object} _createPartition
 * @param {Object} _partitionWebWindowId
 */
function OpenKaseyaWindow(_extRoot, _url, _referringWebWindowId, _createPartition, _partitionWebWindowId, _windowId){
	if (_createPartition) {
		_extRoot.Ext.Ajax.request({
			url: '/vsaPres/Web20/json.ashx',
			params: {
				request: 'CreateWebWindowPartition',
				ReferringWebWindowId: _referringWebWindowId,
				partitionWebWindowId: _partitionWebWindowId
			},
			success: function(_response, _options){
				//load in the model
				var resObj = _extRoot.Ext.JSON.decode(_response.responseText);
				if (resObj && HandleResponseHeader(resObj.header) && resObj.success) {
					if (_windowId) {
						liveConnWin = window.open(AddUrlParam(_url, "referringWebWindowId", resObj.data.partitionWebWindowId), _windowId);
                    }
					else {
						liveConnWin = window.open(AddUrlParam(_url, "referringWebWindowId", resObj.data.partitionWebWindowId));
                    }

					if (!liveConnWin) {
						alert(Ext.ux.LangMgr.PopupBlockerWarning.message + "\r\n\r\n" +
						Ext.ux.LangMgr.SystemInterferenceWarning.message +
						"\r\n" +
						Ext.ux.LangMgr.EnablePopupsMessage.message);
					}
					else {
						liveConnWin.focus();
					}
				}
				else {
					DisplayResponseObject(resObj);
				}
			},
			failure: function(_response, _options){
				AddDebugger();
			}
			
		});
	}
	else {
		liveConnWin = window.open(AddUrlParam(_url, "referringWebWindowId", _referringWebWindowId));
		if (!liveConnWin) {
			alert(Ext.ux.LangMgr.PopupBlockerWarning.message + "\r\n\r\n" +
			Ext.ux.LangMgr.SystemInterferenceWarning.message +
			"\r\n" +
			Ext.ux.LangMgr.EnablePopupsMessage.message);
		}
		else {
			liveConnWin.focus();
		}
	}
}

/**
 *
 * @param {Object} div
 * @param {Object} pageId
 * @param {Object} dataIslandId
 * @param {Object} metaPath
 * @param {Object} fieldName
 * @param {Object} trueValue
 * @param {Object} falseValue
 * @param {Object} dataObjectName
 * @param {Object} rowIndex
 * @param {Object} colIndex
 */
function GridCheckBoxRendererToggle(divId, pageId, dataIslandId, metaPath, fieldName, trueValue, falseValue, dataObjectName, rowIndex, colIndex){
	var div = Ext.getDom(divId)
	//var obj = eval('PageMgrFinder().getModel( pageId, dataIslandId ).records.' + metaPath + '.records.' + dataObjectName + '.data');
	var obj = eval('PageMgrFinder().getModel( pageId, dataIslandId ).' + metaPath + '.data');
	if (div.className == 'x-grid3-check-col-on') {
		div.className = 'x-grid3-check-col';
		eval('obj[rowIndex].' + fieldName + '=\'' + falseValue + '\'')
	}
	else if (div.className == 'x-grid3-check-col') {
		div.className = 'x-grid3-check-col-on';
		eval('obj[rowIndex].' + fieldName + '=\'' + trueValue + '\'')
	}
}

/**
 * Stops the auto-reload functionality of every grid in the context screen
 */
function StopAllGridRefreshes(){
	var ctxScreen = Ext.getCmp('contextScreen');
	if (ctxScreen) {
		var grids = Ext.ComponentQuery.query('kgridbase', ctxScreen);
		for (var i = 0; i < grids.length; i++) {
			if (grids[i].stopAutoRefresh) {
				grids[i].stopAutoRefresh();
            }
        }
	}
}

/**
 * Starts the auto-reload functionality of every grid in the context screen
 */
function ResumeAllGridRefreshes(){
	var ctxScreen = Ext.getCmp('contextScreen');
	if (ctxScreen) {
		var grids = Ext.ComponentQuery.query('kgridbase', ctxScreen);
		for (var i = 0; i < grids.length; i++) { 
			grids[i].startAutoRefresh();
        }
	}
}

function downloadFile(_url){
	var downloadFrame = Ext.get('downloaderFrame');
	if (downloadFrame) {
		downloadFrame.dom.src = _url;
	}
	else {
		var m = Ext.core.DomHelper.append(Ext.getBody(), {
			html: ['<iframe id="downloaderFrame" src="', _url, '" style="display:none"'].join('')
		}, true);
	}
}

/**
 * Handles whether the user clicked yes/no to confirm that they are about to loose all their changes.
 * If they click yes, we clean the data island and close the window, if they click no we will simply
 * return and allow them to continue editing the exiting record on the screen.
 * @param {Object} _btn
 * @param {Object} _text
 */
function windowCloseHandler(_btn, _text){
	if (_btn == "no" || _btn == "cancel") {
		return false;
	}
	else {
		PageMgrFinder().manuallyCleanIsland(this.id, this.id);
		this.close();
	}
}

/**
 * Generates a Unique action Id based on time and randomness
 * @return unique id
 */
function GenerateUniqueActionId(){
	return "k" + GenerateUniqueId();
}

function GenerateUniqueId(){
	return ((new Date()).getTime() + "" + Math.floor(Math.random() * 1000000)).substr(0, 18);
}

/**
 * Reloads the current selector on the page if one exists.  If a page doesn't contain a selector, it should
 * provide a reload screen in the response rather than allowing this function to be called.
 * @param {Object} _pageId
 * @param {Object} _acquirePageNumber
 */
function reloadSelector(_pageId, _acquirePageNumber, _reselectNode, clearSelections){
	var selector = PageMgrFinder().getSelector(_pageId);	
	if (!selector) {
	    return;
	}

	if (clearSelections) {
		PageMgrFinder().clearSelections(selector.pageId, selector.dataIslandId, selector.objectName);		
	}
	
	// determine if we have a grid or tree selector
	if (selector && selector.ownerCt && Ext.ComponentQuery.query('gridpanel', selector.ownerCt).length > 0) {
		selector.loadGridModel(true, false, false, _acquirePageNumber);
	}
	else if (selector && selector.ownerCt && Ext.ComponentQuery.query('treepanel', selector.ownerCt).length > 0) {
		var selNode = selector.getSelectionModel().selected.getAt(0);
		if (selector.clearNodeActions) {
		    selector.clearNodeActions();
		}
						
		if (selector.reloadNode) {
		    selector.reloadNode(selNode); // non-legacy trees
		} else {		    	    		    
		    // legacy tree providers have a cache parameter. make sure we are not reloading from cache.
            var usePurgedDataParam = Ext.isDefined(selector.store.proxy.extraParams.purgeCacheData);	    
		    if (usePurgedDataParam) {
		        selector.store.proxy.extraParams.purgeCacheData = true;
		    }
		    
		    if (!selNode) {
                selNode = selector.getRootNode();
            }

            selector.store.load({node: selNode.data.leaf ? selNode.parentNode : selNode});		    
		    
		    if (usePurgedDataParam) {		    
		        selector.store.proxy.extraParams.purgeCacheData = false;
		    }
		}		
		
		if (_reselectNode) {
			selector.getSelectionModel().deselectAll(true);
			selector.getSelectionModel.fireEvent('selectionChange', selector.getSelectionModel(), selNode);
		}
	}
}

function machineFilterReload(_pageId, _reloadSelector){
	if (_pageId && _pageId != "undefined") {
		// subtab grids loadGridModel wont fire the ajax request if the request newParams dont match the oldParams.  therefore, we need to flush those old params from the grids so that
		// we can reread the data for those subtab grids that allowPaging.
		var ctxScreen = Ext.getCmp('contextScreen');
		if (ctxScreen) {
			var grids = Ext.ComponentQuery.query('kgridbase', ctxScreen);
			for (var i = 0; i < grids.length; i++) {
				grids[i].oldParams = {};
				grids[i].gridPageNumber = 1;
		    }
		}
		
		if (_reloadSelector == "false") {
			reloadSelection(_pageId);
		}
		else {
			reloadSelector(_pageId, false, true);
		}
	}
	else {
		// if we dont get a pageId, then reload the entire current context
		ReloadCurrentContext();
	}
}

function reloadSelection(_pageId){
	//if we have a grid selector, make sure that all the same record(s) are selected again after the action
	var selector = PageMgrFinder().getSelector(_pageId);
	
	if (selector && selector.ownerCt && Ext.ComponentQuery.query('gridpanel', selector.ownerCt).length > 0) {
		if (selector.selModel.selected.length == 1) {
			var selRecord = selector.selModel.selected.getAt(0);
			selector.selModel.deselectAll(true);
			selector.selModel.select(selRecord);
		}		
	}
	else if (selector && selector.ownerCt && Ext.ComponentQuery.query('treepanel', selector.ownerCt).length > 0) {
		var selNode = selector.selected.getAt(0);
		if (selNode) {
			selector.selModel.deselectAll(true);
			selector.selModel.select(selNode);
		}
	}		
}

/**
 * Fixes which buttons are enabled/disabled in the toolbar based on how many selections are currently on the page
 * @param {Object} _tb
 * @param {Object} _selectionCount
 */
function FixToolbar(_tb, _selectionCount){
	if (_tb) {
		for (var i = 0; i < _tb.items.length; i++) {
		    var toolbarItem = _tb.items.items[i];
		    toolbarItem.disable(); // default to a disabled state

		    if (toolbarItem.initialEnabledState) {
				var minSelReq = 0;
				if (toolbarItem.initialConfig.controllerConfiguration && toolbarItem.initialConfig.controllerConfiguration.minSelectionRequirement) {
				    minSelReq = Number(toolbarItem.initialConfig.controllerConfiguration.minSelectionRequirement.replace(/Item/, ""));
				}
				
				var maxSelReqStr = 'N';
				if (toolbarItem.initialConfig.controllerConfiguration && toolbarItem.initialConfig.controllerConfiguration.maxSelectionRequirement) {
				    maxSelReqStr = toolbarItem.initialConfig.controllerConfiguration.maxSelectionRequirement.replace(/Item/, "");
				}
				
				var maxSelReq = 0;
				if (maxSelReqStr == 'N') {
				    maxSelReq = 100000000000;
				}
				else {
				    maxSelReq = Number(maxSelReqStr);
				}
				
				if (_selectionCount >= minSelReq && _selectionCount <= maxSelReq) {
				    toolbarItem.enable();
				}
				
				// check for sub-items and mark them as well
				if (toolbarItem.menu && toolbarItem.menu.items) {
				    FixToolbar(toolbarItem.menu, _selectionCount);
					
					var enabledCount = 0;
					for (var j = 0; j < toolbarItem.menu.items.length && enabledCount == 0; j++) {
					    if (!toolbarItem.menu.items.items[j].disabled) {
					        enabledCount++;
					    }
					}
					
					// if none of the sub-items are enabled, then disable the root as well
					if (enabledCount == 0) {
					    toolbarItem.disable();
					}
				}
			}
		}
	}
}

/**
 * Merges nodes in a tree structure rather than blindly removing all of them and redrawing all the nodes in the tree
 * Intelligently tries to update the nodes in the node's structure by updating text, and showing modified versions
 * of the node by changing the css class on the node image.  Also adds/removes nodes as they are added/removed from
 * the structure.  You cannot call this function if you are drag-n-dropping a node, because a merge doesn't detect
 * positional changes in the structure, only if nodes are added/removed from the current node.
 * @param {Object} _node
 * @param {Object} _config
 * @param {Object} _scope
 * @param {Object} _editMode
 */
function MergeNodes(_node, _config, _scope, _editMode, _selector){
	// if this is the root node, then validate the length of the name and description.  if too long, then mark the iconCls with the error class.
	if (_node.data.root && _config && _config.length > 0 && _config[0].iconCls && !_config[0].iconCls.endsWith('-mod')){
		// description length test
		var valid = true;
		if (_config[0].description && _config[0].description.length > 1000) {
			valid = false;
        }

		// name length test
		if (_config[0].text && _config[0].text.length > 100) {
			valid = false;
        }
		
        if (!valid) {
			_config[0].iconCls = _config[0].iconCls + "-mod";
        }
	}
	
    if (_config) {
		for (var i = 0, len = _config.length; i < len; i++) {
			if (_editMode && (_config[i].nodeDirty || _config[i].nodeInvalid)) {
				if (_config[i].iconCls && !_config[i].iconCls.endsWith('-mod')) {
					_config[i].iconCls = _config[i].iconCls + "-mod";
				}
			}
			
            var oldNode = _node.findChild("id", _config[i].id);
			if (!oldNode) {
				//if we can't find the node, then its a new node,
				//and we need to figure out where to put it
				if ((i + 1) < len) {
					var nextNode = _node.findChild("id", _config[i + 1].id);
					if (nextNode) {
						_node.insertBefore(_scope.createNode(_config[i]), nextNode)
					}
					else {
						_node.appendChild(_scope.createNode(_config[i]));
					}
				}
				else {
					_node.leaf = false;
					var hadNodes = _node.hasChildNodes();
					_node.appendChild(_scope.createNode(_config[i]));
					// hack: if adding to a node thats currently empty, then expand it
					if (!hadNodes) {
                        _node.expand();
                    }
				}
			}
		}
		
		for (var i = 0; i < _node.childNodes.length; i++) {
			var found = false;
			for (var j = 0; j < _config.length && !found; j++) {
				if (_node.childNodes[i].id == _config[j].id) {
					found = true;
					
                    var iconEl = _node.childNodes[i];
					if (iconEl) {
						if (_node.childNodes[i].data.iconCls) {
                            iconEl.set(_node.childNodes[i].data.iconCls, '');
                        }

						iconEl.addCls(_config[i].iconCls);
					}
					
                    _node.childNodes[i].data.iconCls = _config[i].iconCls;
					
                    if (_node.childNodes[i].text != _config[i].text) {
						//_node.childNodes[i].setText((_config[i].text ? _config[i].text : ''));
						_node.childNodes[i].set('text', (_config[i].text || ''));
					}
					
                    MergeNodes(_node.childNodes[i], _config[i].children, _scope, _editMode, _selector);
					
                    if (_selector) {
						if (_node.childNodes[i].data.nodeCategory == "CABINET" || (_node.childNodes[i].data.nodeCategory == "FOLDER" && _node.childNodes[i].data.rootNodeFK == "1") && i < 2) {
							_node.childNodes[i].expanded = true;
						}
						else if (_node.childNodes[i].data.nodeCategory == "FOLDER") {
							_node.childNodes[i].expanded = false;
						}
					}
				}
			}
			
            if (!found) {
				_node.removeChild(_node.childNodes[i]);
				i--;
			}
		}
	}
}


/**
 * Verifies that the current user has access to the funcListId provided in the currentLoadConfig.
 * @param {Object} _userData
 * @return true if the user has access, false otherwise
 */
function verifyUserAccess(_userData){
	res = false;
	if (_userData && _userData.currentLoadConfig && _userData.currentLoadConfig.activeId && _userData.currentLoadConfig.activeId.length > 0) {
		// looks for a module or a subordinate folder or item in the user module collection
		mod = FindModuleByFuncListId(_userData.applications[0].modules, _userData.currentLoadConfig.activeId, false);
		if (mod) {
			res = true;
		}
	}
	
	return res;
}

// asp page utility methods


/**
 * ASP Page Utility Method
 * Closes the Window hosting the asp page by providing the windowId of the component to close.
 * @param {Object} _windowId
 */
function CloseContainerWindow(_windowId){
	if (_windowId && _windowId.length > 0) {
		var win = Ext.getCmp(_windowId);
		if (win) {
            win.close();
        }
	}
}


/**
 * ASP Page Utility Method
 * Closes the Window hosting the asp page by providing the windowId of the component to close, and tells the
 * underlying framework to reload the currently selected navigation item's data.
 * @param {Object} _windowId
 */
function CloseContainerWindowAndReload(_windowId){
	if (_windowId && _windowId.length > 0) {
		var win = Ext.getCmp(_windowId);
		if (win && win.initialConfig && win.initialConfig.pageId) {
            reloadSelector(win.initialConfig.pageId);
        }
	}

	CloseContainerWindow(_windowId);
}


/**
 * ASP Page Utility Method
 * Helper function to get the WindowId based on the passed url.  Useful for closing the Window an asp page is contained in.
 * @param {Object} _href
 * @return The hosting window id
 */
function GetContainerWindowId(_href){
	// check if the windowId has been provided.  this is configurable on the Controller xml configuration.
	return Ext.Object.fromQueryString(_href).kapfwWinId;
}

function openWindowWithPost(url, name, options, params, isSingleRecordController, _windowId, winType) {
	// use the data object name and the selected records to determine if the same window should be used.  if we already have
	// an edit window open for a particular record, then we should reuse that window.
    var windowName = ' ';
    /*if (!windowName) 
    {
        // if no name has been provided, then we will generate a window name based on the selection criteria.
        windowName = 'classicActionWindow';
        if (params && params.dataObjectName) 
            windowName += params.dataObjectName;
    }*/
	// only added selected record criteria on a window if its a single record controller
    if (isSingleRecordController) {
        if (params && params.selectedRecords) {
			var x = Ext.JSON.decode(params.selectedRecords);
            if (x && x.length > 0 && x[0].id) {
				windowName += escape(x[0].id);
			}
			else if (x && x[0] && x[0].id) {
				windowName += escape(x[0].id);
			}
		}
	}
	
    if (params.parentid) {
		// attempt to obtain any marked objects to ensure uniqueness.  we will select only the first one
        if (params.markedObjects) {
			windowName += params.parentid;
            if (params.dataObjectName) {
				var g = Ext.JSON.decode(params.markedObjects);
                if (g && g.map && g.map[params.dataObjectName] && g.map[params.dataObjectName].selections && g.map[params.dataObjectName].selections.items && g.map[params.dataObjectName].selections.length > 0) {
					windowName += g.map[params.dataObjectName].selections.items[0].id;
				}
			}
		}
	}

	// KERBE: work around IE's window.open limitations	
	if (winType == 'SINGLE_USE_CLASSIC_WINDOW') {
	    var random = Math.round(Math.random() * 999) + 100;
	    windowName = params.windowTitle || windowName; // use the specified window name if there is one
	    windowName = windowName + random; // ensure the window name is unique for each click which will ultimately allow multiple windows to be spawned instead of window reuse
	    windowName = Ext.util.Format.trim(windowName);
	    windowName = windowName.replace(/\s+/g, '999'); // replace spaces with a unique sequence so we can do another replace on the server
	}

	if (Ext.isIE) {
	    windowName = windowName.replace(/[^a-zA-Z0-9]+/g, ''); // remove all non alpha-numeric characters in IE, as they cause javascript errors. thanks, Microsoft.
	}
	
	var newWindow = window.open('/vsaPres/_blank.html', windowName, options);
    if (!newWindow) {
		popupsBlocked();
		return false;
	}
	
    if (params.parentid) {
		PageMgrFinder().registerChildControllerWindowId(params.parentid, newWindow);
	}
    else {
		// if no parent, then hook the actions to the user_store which is essentially the shell page
		PageMgrFinder().registerChildControllerWindowId('user_store', newWindow);
    }
	
	// for(var p in params)
	// if(p == 'dataIsland')
	// { 	
	// var y = Ext.JSON.decode(params[p]);
	// params[p] = escapeObject(y);
	// //params[p] = escape(params[p]);
	// }
	
	var html = "";
	html += "<html><head></head><body><form id='formid' method='post' action='" + url + "'>";
	html += "<input type='hidden' name='actionid' value='" + params.actionid + "'/>";
	html += "<input type='hidden' name='referringWebWindowId' value='" + params.referringWebWindowId + "'/>";
	html += "<input type='hidden' name='params' value='" + Ext.JSON.encode(params).replace("'", "\\\\u0027") + "'/>"; // replace single-quotes with escaped and hex value so avoid parsing errors in classic window "params"
	html += "<input type='hidden' name='windowName' value='" + windowName + "'/>";
	html += "<input type='hidden' name='winType' value='" + winType + "'/>";
	html += "</form><script type='text/javascript'>";
	html += "document.getElementById(\"formid\").submit();";
	html += "</script>";
	html += "</body>";
	html += "</html>";

	newWindow.document.write(html);
	
	return newWindow;
}

function escapeObject(_o) {	
    if (_o) {
		for (key in _o) { // TODO: use Ext.iterate
			if (typeof _o[key] == 'string' && key == 'txtdescription') {
				//		_o[key] = Ext.util.Format.htmlEncode(_o[key]);
			}
			else if (typeof(_o[key]) == 'object') {
				escapeObject(_o[key]);
			}
		}
	}

	return _o;
}

function CallModuleController(_module, firstItem, mod, _pageId) {
    var userData = PageMgrFinder().getUser();
   
    var fakeButton = {};
    fakeButton.initialConfig = {};
    fakeButton.dataObjectName = null;
    fakeButton.initialConfig = {
        website: mod.website,
        referringWebWindowId: userData.webWindowId,
        controllerConfiguration: mod.moduleController,
        pageId: _pageId
    };

    var params = GetControllerParams(fakeButton, null, true);

    Ext.Msg.wait(Ext.ux.LangMgr.ProcessingText.message, Ext.ux.LangMgr.ProcessingText.title, {interval: 200 });

    Ext.Ajax.request({
        url: mod.website,
        params: params,
        success: function(_response, _options) {
            PageMgrFinder().pageDirty(false);

            Ext.Msg.hide();

            var resObj = Ext.JSON.decode(_response.responseText);

            if (resObj) {
                HandleResponseHeader(resObj.header);
            }

            if (!resObj || !resObj.success) {
                DisplayResponseObject(resObj);
                return;
            }

            var redirect = null;
            if (resObj && resObj.data.redirectFuncListID) {
                redirect = resObj.data.redirectFuncListID;

                var redirectModule = FindItemByFuncListId(userData.applications[0].modules, redirect);

                // if we have receive a completeAlert, then show it now
                if (resObj.data.completeAlert) {
                    showMessageBox(resObj.data.completeAlertTitle || ' ', resObj.data.completeAlert);
                }

                LoadModuleContent(_module, redirectModule, mod, redirect);

                NavigateTo({ activeId: redirect });

                return;
            }
            
            // if we have receive a completeAlert...and not a redirect funcId...show it now
            if (resObj.data.completeAlert) {
                Ext.Function.defer(showMessageBox, 2000, this, [resObj.data.completeAlertTitle || ' ', resObj.data.completeAlert]);
            }                                   

            LoadModuleContent(_module, firstItem, mod, redirect);
        }
    });												    
}

function LoadModuleClick(_module){
	for (var x = 0; x < PageMgrFinder().items.length; x++) {
		if (PageMgrFinder().items[x].id && PageMgrFinder().items[x].id != 'user_store') {
			PageMgrFinder().unregisterPage(PageMgrFinder().items[x].id);
			x--;
		}

		// flush out any cached node action collections.
		// this will limit reuse of node type actions in lieu of conserving memory in the browser.
		Kaseya.web.managers.NodeTypeActions.unregisterIslands();
	}
	
	// this is a physical click on the module.  reset the load configuration to use this module's funcListID
	var userData = PageMgrFinder().getUser();
	
	var mod = FindModule(userData.applications[0].modules, _module.id);
	if (mod) {
	    var modFirstItem = FindFirstItemInModule(mod);
	    
	    if (mod.moduleController && mod.moduleController.name) {
	        CallModuleController(_module, modFirstItem, mod, PAGE_ID);
	    } else {
	        LoadModuleContent(_module, modFirstItem, mod);
	    }
	}
}

function LoadModuleContent(_module, modItem, mod, redirectId) {
    var activeId = modItem ? modItem.funcListID : mod.funcListID;
    if (redirectId) {
        activeId = redirectId;
    }
    
    SetUserConfig({
        activeId: activeId,
        recordId: '',
        activeAction: '',
        customParams: '',
        filterName: '',
        dimensions: [],
        resetFilter: false
    });

    SetHelpContext({
        helpId: (modItem && modItem.helpId) ? modItem.helpId : mod.helpId,
        helpVersion: mod.helpVersion,
        helpModule: mod.helpModule
    });

    LoadModule(_module);
}

function LoadModule(_module){
	var userData = PageMgrFinder().getUser();
	_module.ownerCt.getLayout().activeItem = _module.id;
	
	var mod = FindModule(userData.applications[0].modules, _module.id);
	// if this is loading the module through a load configuration, meaning that it will be loading a funcListID different than the module being loaded, then dont bother to load the module.
	
	// hide the old context screen from view while the screen is being rebuilt
	var cs = Ext.getCmp('contextScreen');
	if (cs) {
		try {
			// if there is an onbeforeunload event attached to whatever the context screen is hosting,
			// run it
			var cc = Ext.query("iframe", Ext.getCmp('contextScreen').el.dom);
			for (var i = 0; i < cc.length; i++) {
			    cc[i].src = "/vsaPres/_blank.html";
			}

            var cp = Ext.getCmp('CenterPanel');	
            if (cp && cp.el) {                        					
                cp.el.mask();
            }		
		} 
		catch (_exc) {
			try {
				AddDebugger();
				cs.clearListeners();
				cs.removeAll();
			} 
			catch (_ex) {
				AddDebugger();
			}
		}
	}

	for (var x = 0; x < PageMgrFinder().items.length; x++) {
		 // kerbe:  actions cant get flushed since we now support classic window actions.  they start with a k, which is horrible and
		 // needs improvement.
		 if (PageMgrFinder().items[x].id && PageMgrFinder().items[x].id != 'user_store' && PageMgrFinder().items[x].id.indexOf('k') != 0) {
			  PageMgrFinder().unregisterPage(PageMgrFinder().items[x].id);
			  x--;
		 }

		 // flush out any cached node action collections.
		 // this will limit reuse of node type actions in lieu of conserving memory in the browser.
		 Kaseya.web.managers.NodeTypeActions.unregisterIslands();
    }
	
	if (userData.currentLoadConfig && userData.currentLoadConfig.activeId != mod.funcListID) {
	// this means that load configuration is going to load another target, such as an item within this module, so dont bother loading the module screen.
	}
	else {
		MessageSysProvider.GetScreen(_module.funcListID, PAGE_ID, userData.currentHelpContext.helpVersion, userData.currentLoadConfig.filterName, Ext.JSON.encode(userData.currentLoadConfig.dimensions) || '', userData.currentLoadConfig.resetFilter, Ext.JSON.encode(userData.currentLoadConfig.customParams) || '', WEB_WINDOW_ID, function(e, _response){
			if (_response && _response.status) {
				//load in the model
				var resObj = Ext.JSON.decode(_response.result);
				if (resObj && HandleResponseHeader(resObj.header) && resObj.success) {
					SetUserConfig({ resetFilter: false });
					var cp = Ext.getCmp('CenterPanel');
					for (var i = 0; i < cp.items.length; i++) {
						Ext.destroy(cp.items.items[i]);
					}
					cp.items.clear();
					cp.add(resObj.data);
					
					cp.getLayout().setActiveItem(cp.items.length - 1);
					cp.doLayout();
				}
				else {
					DisplayResponseObject(resObj);
				}
			}
			else{
				AddDebugger();
			}
		});
	}
}

function LoadUserPreferences(preferences){
	if (preferences) {
	    SetUserPreferences(preferences);
	} else {
	    MessageSysProvider.GetUserPreferences(WEB_WINDOW_ID, function(e, response){
		    SetUserPreferences((e && e.success && HandleResponseHeader(e.header) && e.data) ? e.data : {});
	    });
	}
}

function SetUserPreferences(preferences) {   	
	var provider = Ext.create('Ext.ux.state.HttpProvider', {
        url: '/vsapres/web20/providers/StateProvider.ashx',
        readBaseParams: {cmd: 'readState', webWindowId: WEB_WINDOW_ID},
        saveBaseParams: {cmd: 'saveState', webWindowId: WEB_WINDOW_ID},
        autoRead: false,
        delay: 0
    });        
	
	Ext.state.Manager.setProvider(provider);
	
	// re-format initial preferences into an array
	var prefs = [];
	Ext.iterate(preferences, function(preferenceProp) {
	    prefs.push({name: preferenceProp, value: preferences[preferenceProp]});
	}, this);
	
	Ext.state.Manager.getProvider().initState(prefs);

    // notify a few controls that state has been completely loaded
    var mt = Ext.getCmp('modTree'); 
    if (mt) {
        mt.fireEvent('stateLoaded', mt);
    }

    var nBar = Ext.getCmp('NotificationBar');
    if (nBar) {
        nBar.fireEvent('stateLoaded', nBar);
    }

    var dashBar = Ext.getCmp('Dashbar');
    if (dashBar) {
        dashBar.fireEvent('stateLoaded', dashBar);
    }
}

function LoadUser(_params, user){	
	var params = {
		request: 'getUserDataStore',
		ReferringWebWindowId: WEB_WINDOW_ID,
		browserOffset: Ext.Date.format(new Date(), 'c')
	};
	
	Ext.applyIf(params, _params);
	
	if (params.reloadApp) {
		MessageSysProvider.GetUserDataStore(WEB_WINDOW_ID, params.client || '', params.role || '', params.scope || '', Ext.Date.format(new Date(), 'c'), function(e, response){
			top.window.location = top.window.location.href.split("#")[0];
		});
	}
	else {
		// lock down the browser while the user loads
	    var vp = Ext.getCmp('PageShellViewPort');
	    if (vp) {
	        vp.disable();
	    }
	    
	    if (user) {
	        MessageSysProvider.GetUserDataStore1(WEB_WINDOW_ID, params.client || '', params.role || '', params.scope || '', Ext.Date.format(new Date(), 'c'), false, function(r) { 
	            // we still need to set some variables on the server (such as browser time offset), but we don't need the user data
	            // set the statuses earlier since we are still getting the header
			    var r = Ext.JSON.decode(r);
			    if (r && r.success && HandleResponseHeader) {
			        HandleResponseHeader(r.header);
			    };
	        });        	        	        	        
	        
            // update the user browser timezone offset
            var d = new Date();
            user.utcOffsetBrowser = -d.getTimezoneOffset();
	        
	        SetUserStore(user);	                                
            
            if (vp) { 
                vp.enable();
            }
	    } else {
	        MessageSysProvider.GetUserDataStore(WEB_WINDOW_ID, params.client || '', params.role || '', params.scope || '', Ext.Date.format(new Date(), 'c'), function(e, _response) {
	            try {
	                    var r = Ext.JSON.decode(_response.result);

	                    if (r && HandleResponseHeader(r.header) && r.success) {
	                        SetUserStore(r.data);	                    
	                    }
	                    else {
	                        DisplayResponseObject(r);
	                    }

	                    var vp = Ext.getCmp('PageShellViewPort');
	                    if (vp) { 
	                        vp.enable();
	                    }
	                }
	                catch (_ex) {
	                    // lock down the browser while the user loads
	                    var vp = Ext.getCmp('PageShellViewPort');
	                    if (vp) { 
	                        vp.enable();
	                    }
	                    
	                    if (_response && _response.responseText) {
	                        _ex.responseText = _response.responseText;
	                    }
	                    
	                    DisplayException(_ex);
	                }
	            });
	    }
	}
}

function SetUserStore(user) {
    var r = { data: user};
    
    // adjust the navigation toolbar based on user priviledges and resize to fix the toolbar buttons available
    var navigator = Ext.getCmp('Navigator');
    var navigatorToolbar = Ext.getCmp('NavToolBar');
    if (navigator && navigatorToolbar) {
        var navToolbarWidth = navigator.width;        
        var minNavigatorWidth = navigator.minNavigatorWidth;
        var navigatorButtonWidth = navigator.navigatorButtonWidth;
        
        if (!r.data.allowsAdminNotes) {
            navigatorToolbar.notesButton.hide();
            navToolbarWidth = navToolbarWidth - navigatorButtonWidth;
        }
        else {
            navigatorToolbar.notesButton.show();
        }

        if (!r.data.allowsStatus) {
            navigatorToolbar.statusButton.hide();
            navToolbarWidth = navToolbarWidth - navigatorButtonWidth;
        }
        else {
            navigatorToolbar.statusButton.show();
        }

        if (!r.data.allowsHelp) {
            navigatorToolbar.helpButton.hide();
            navToolbarWidth = navToolbarWidth - navigatorButtonWidth;
        }
        else {
            navigatorToolbar.helpButton.show();
        }

        if (!r.data.enableTester) {
            navigatorToolbar.showTesterButton.hide();
            navToolbarWidth = navToolbarWidth - navigatorButtonWidth;
        }
        else {
            navigatorToolbar.showTesterButton.show();
        }

        navigator.setWidth((navToolbarWidth < minNavigatorWidth ? minNavigatorWidth : navToolbarWidth));

        Ext.getCmp('PageShellViewPort').doLayout();
    }

    // if we already had a user store, we need to ensure we dont lose the prior recordId in the userConfig.  if
    // the activeId coming back in the new userConfig matches the old activeId, then retain the recordId for the old
    var userData = PageMgrFinder().getUser();
    if (userData && userData.currentLoadConfig && r && r.data && r.data.currentLoadConfig && userData.currentLoadConfig.activeId == r.data.currentLoadConfig.activeId) {
        if (!r.data.currentLoadConfig.recordId || r.data.currentLoadConfig.recordId == '') r.data.currentLoadConfig.recordId = userData.currentLoadConfig.recordId;
    }

    PageMgrFinder().setModel('user_store', 'user_store', r.data, true);   
                     
    if (typeof(setMonthNumbers) != 'undefined'){
        setMonthNumbers(PageMgrFinder().getUser().currentCultureCode);
    }

    LogToConsole('User Authenticated.  User Attributes');
    LogToConsole(r.data);

    loadDateConfiguration({
        format: r.data.timeFormat,
        browserOffset: r.data.utcOffsetBrowser,
        serverOffset: r.data.utcOffsetDb,
        fixedOffset: r.data.utcOffsetFixed,
        offsetPref: r.data.adminTimePref
    });

    if (r.data.returnURL) {
        logoffURL = r.data.returnURL;
    }

    var bannerBar = Ext.getCmp('BannerBar');
    if (bannerBar && bannerBar.isVisible()) {
        bannerBar.initializeUserControls();
        bannerBar.setWelcomeName(r.data.name);
        bannerBar.setClientUrl(r.data.partnerBannerUrl);

        bannerBar.startMessageWatch(r.data.pollingInterval);

        // determine if the session timer should be shown
        if (r.data.sessionTimerActive) {
            bannerBar.showSessionTimer(r.data.sessionTimers, r.data.allowMultipleSessionTimers);
        }
        else {
            bannerBar.hideSessionTimer();
        }

        // determine if the role and scope comboboxes should be shown
        var showRole = r.data.roles.length > 1;
        for (var roleIndex = 0; roleIndex < r.data.roles.length && !showRole; roleIndex++) {
            if (r.data.roles[roleIndex].name == 'Master' || r.data.roles[roleIndex].name == 'System') {
                showRole = true;
            }
        }

        var showScope = r.data.scopes.length > 1;
        for (var scopeIndex = 0; scopeIndex < r.data.scopes.length && !showScope; scopeIndex++) {
            if (r.data.scopes[scopeIndex].name == 'Master' || r.data.scopes[scopeIndex].name == 'System') {
                showScope = true;
            }
        }

        // if we need to supress the tenant/role/scope then hide them
        /*var userTb = Ext.get('usertb-div');
        if (!showRole && !showScope && r.data.suppressTenantScopeRoleSelection) {
            //bannerBar.scopeLabel.hide();
            //bannerBar.scopeCombo.hide();
            //bannerBar.roleLabel.hide();
            //bannerBar.roleCombo.hide();

            //userTb.setWidth(userTb.getWidth() - 250);
            //userTb.alignTo(document, 'tr-tr');
            
            //if (Ext.isIE) {
                //userTb.alignTo(document, 'tr-tr'); //This needs to be called twice for IE because its horrible --Ryan
            //}
        }

        // if we allow tenant and its not suppressed, then show it
        if (r.data.allowsMultiTenant && !r.data.suppressTenantScopeRoleSelection) {
            //bannerBar.tenantLabel.show();
            //bannerBar.tenantCombo.show();

            //userTb.setWidth(userTb.getWidth() + 125);
            //userTb.alignTo(document, 'tr-tr');
            
            //if (Ext.isIE) {
                //userTb.alignTo(document, 'tr-tr'); //This needs to be called twice for IE because its horrible --Ryan
            //}
        }

        if (r.data.allowEffectiveDate) {
            if (bannerBar.effDate.hidden) {
                bannerBar.effDateLabel.show();
                bannerBar.effDate.show();
                bannerBar.effDate.setValue(new Date());

                //Ext.get('usertb-div').setWidth(Ext.get('usertb-div').getWidth() + 175);
            }
            //userTb.alignTo(document, 'tr-tr');
            
            //if (Ext.isIE) {
            //    userTb.alignTo(document, 'tr-tr'); //This needs to be called twice for IE because its horrible --Ryan
            //}
        }

        // if there is no reason to render the userToolbar, then don't bother
        // if (showRole || showScope || r.data.allowEffectiveDate || (r.data.allowsMultiTenant && !r.data.suppressTenantScopeRoleSelection) || !r.data.suppressTenantScopeRoleSelection) {
        //    bannerBar.userToolbar.render(bannerBar.usertbDiv);
        //    bannerBar.userToolbar.show();
        // }*/
    }
       
    LoadConfig(PageMgrFinder().getModel('user_store', 'user_store'));                                        

    //construct the bookmark tree loaded in the user
    var bookmarkTree = BuildBookmarksTree(r.data.bookmarks, new Ext.toolbar.Toolbar({
        items: [{
            icon: '/vsaPres/App_Themes/0/images/SIZE16/General/bookmark.png',
            cls: 'x-btn-text-icon',
            text: Ext.ux.LangMgr.NavigationToolbar.OrganizeBookmarks,
            pageId: 'Bookmark',
            dataIslandId: 'user',
            dataObjectName: 'user',
            referringWebWindowId: WEB_WINDOW_ID,
            website: ACTION_URL,
            handler: ControllerClickHandler,
            controllerConfiguration: {
                conduit: 'vsaPres',
                className: 'OrganizeBookmarks',
                plugin: 'Kaseya.Web.Bookmarks',
                host: 'EMBEDDED_WINDOW',
                behavior: 'START',
                width: 700,
                height: 350,
                helpId: '5422'
            }
        }]
    }), true);

    var bm = Ext.getCmp('Bookmarks');
    if (bm && bm.items) {
        bm.items.clear();
        bm.add(bookmarkTree);
        bm.doLayout();
    }
    var moduleTree = BuildModuleTree(r);                                   
    if (moduleTree) {
        var wp = Ext.getCmp('NavigationDisplayPanel');
        if (wp) {
            wp.insert(0, moduleTree);
            wp.getLayout().setActiveItem(0);
        }
    }
}

/**
 * Helper function that takes the provided Node and goes to retrieve the screen for that particular selected item in the
 * Navigation control.  If it is required, it will rebuild the current screen, updates the User's current configuration,
 * updates the User's current Help Context, and retrieves the screen from the web server for the provided node
 * @param {Object} _node
 * @param {Object} _event
 */
function OnGetScreen(view, _node, item, index, _event){
	if (_node.data.moduleNodeType == "FOLDER") {		
		return false;
	}
    else if(_node.data.moduleNodeType === 'ITEM' && _node.childNodes && _node.childNodes.length > 0){
        _node = _node.childNodes[0];
    } 
	
	LogToConsole(_node.text + ' was clicked');
	LogToConsole(_node.data);
	// // terminate last request.  ideally we would have the transactionid for the last screen load
	// if( _event )
	// Ext.Ajax.abort();
	//If the menu item is configured to collapse the navigation control, then automatically do that now
	if (_node.data.collapseNavigation) {
		Ext.getCmp('Navigator').collapse();
	}
	
	var userData = PageMgrFinder().getUser();
	// check if the user license limit is exceeded.  if so, then display the warning message on any click of the navigator
	
	if (userData.licenseLimitExceeded) {
		if(userData.isMultiTenant){
		    // create the interaction controller with the name "expiredLicenseSaas". 
		    // this will launch a dialog window to allow users to cancel active sessions
		    var interactionController = CreateInteractionControllerConfig('SaasDaemon', 'SaasWorker', 'ClearSessions', null, null, PAGE_ID, 'expiredLicenseSaas', { windowTitle: Ext.ux.LangMgr.User.LicenseLimitExceededTitle, windowWidth: '800', windowHeight: '600'})
		    ControllerConfigurationStart(WEB_WINDOW_ID, ACTION_URL, interactionController, null, true, PAGE_ID, null);		    				    
		}
		else{
    		DisplayErrorMessage(Ext.ux.LangMgr.User.LicenseLimitExceededTitle, Ext.ux.LangMgr.User.LicenseLimitExceeded);
		}
		return false;
	}
	
	var showLoading = false;
	
	// if we have a module controller defined, then load that.
	var mod = FindModuleByFuncListId(userData.applications[0].modules, _node.data.funcListID, false);
	
	// rebuild the screen if the activeId has changed or we dont have a selector registered with the page manager.  this will be the case on the initial load when we apply the last active id from user preferences
	var rebuildScreen = true;

    if (userData && userData.currentLoadConfig && userData.currentLoadConfig.activeId != _node.data.funcListID) {
		SetUserConfig({
			activeId: _node.data.funcListID,
			recordId: '',
			activeAction: '',
			customParams: '',
			filterName: '',
			dimensions: [],
			resetFilter: false
		});

		rebuildScreen = true;
	}
	else {
		SetUserConfig({
			activeId: _node.data.funcListID,
			recordId: userData.currentLoadConfig.recordId,
			activeAction: userData.currentLoadConfig.activeAction,
			customParams: userData.currentLoadConfig.customParams,
			filterName: userData.currentLoadConfig.filterName,
			dimensions: userData.currentLoadConfig.dimensions,
			resetFilter: userData.currentLoadConfig.resetFilter
		});
		
		// if we have a selector, then we have already build the screen.  if we have a filter specified, then we need to rebuild the screen as well
		//If we reset the filter, then the filterName is going to be blank, so we can't check to see if its empty
		var sec = PageMgrFinder().getSelector(PAGE_ID);
		if (userData.currentLoadConfig.filterName != null || userData.currentLoadConfig.dimensions != null || (sec && sec.initialConfig && sec.initialConfig.dummySelector == 'True') || (sec && sec.dummySelector)) {
			rebuildScreen = true;
		}
		else {
			// if _event is undefined then this means it was not a true click of the node.  if a true click of the node, rebuild the screen so we dont incur memory drain
			if (sec && !_event) {
				rebuildScreen = false;
				// do not flush page manager since its a reclick
				for (var x = 0; x < PageMgrFinder().items.length; x++) {
					if (PageMgrFinder().items[x].id && PageMgrFinder().items[x].id != 'user_store') {
						PageMgrFinder().unregisterDataModels(PageMgrFinder().items[x].id);
					}
					
                    // flush out any cached node action collections.
					// this will limit reuse of node type actions in lieu of conserving memory in the browser.
					Kaseya.web.managers.NodeTypeActions.unregisterIslands();
				}
			}
			else {
				rebuildScreen = true;
            }
		}
	}
	
    if (mod) {
		SetHelpContext({
			helpId: _node.data.helpId,
			helpModule: mod.helpModule,
			helpVersion: mod.helpVersion
		});
	}
	
	if (rebuildScreen) {
        if (_node.data.kxtype) {
			// onGetScreenSuccess just adds in the control, so that's what we're going to do too
		    MessageSysProvider.TouchScreen(WEB_WINDOW_ID, _node.data.funcListID, function(e, response) {
		        var resp = Ext.JSON.decode(e);
		        HandleResponseHeader(resp.header)  
		    });

		    this.add({
				user: PageMgrFinder().getUser(),
				currentItem: _node,
				xtype: _node.data.kxtype
			});

			this.getLayout().setActiveItem(this.items.length - 1);
			this.doLayout();
		}
		else {
			if (_node && _node.data && _node.data.contextName && (_node.data.contextName.indexOf('kurl=') == 0 || _node.data.contextName.indexOf('url=') == 0)) {
			    MessageSysProvider.TouchScreen(WEB_WINDOW_ID, _node.data.funcListID, function(e, response) {
			        var resp = Ext.JSON.decode(e);
			        HandleResponseHeader(resp.header)
			    });

				if (_node.data.contextName.indexOf('kurl=') == 0) {
					InsertScreen({
						xtype: 'kaseyascreen',
						id: 'contextScreen',
						url: _node.data.contextName.replace('kurl=', ''),
						customParams: ((userData && userData.currentLoadConfig && userData.currentLoadConfig.customParams)?userData.currentLoadConfig.customParams:{})
					}, Ext.getCmp('CenterPanel'));
				}
				else if(_node.data.contextName.indexOf('port=') >= 0)  {
					InsertScreen({
						xtype: 'kurlscreen',
						id: 'contextScreen',
						url: _node.data.contextName.replace('port=', ''),
						customParams: ((userData && userData.currentLoadConfig && userData.currentLoadConfig.customParams)?userData.currentLoadConfig.customParams:{})
					}, Ext.getCmp('CenterPanel'));
				}

				else {
					InsertScreen({
						xtype: 'kurlscreen',
						id: 'contextScreen',
						url: _node.data.contextName.replace('url=', ''),
						customParams: ((userData && userData.currentLoadConfig && userData.currentLoadConfig.customParams)?userData.currentLoadConfig.customParams:{})
					}, Ext.getCmp('CenterPanel'));
				}
			}
			else {
				if (_node.data.dataProvider && _node.data.dataProvider.IsCoreProvider) {		    
                    showLoading = true;
                    
                    var eventRequest = new Kaseya.Presentation.Models.Messages.EventRequest({
                            EventName: 'Load',
                            ControlName: 'Screen',
                            DispatchConfiguration: {
                                conduit:  _node.data.conduit,
                                plugin: _node.data.plugin,
                                className: _node.data.className
                            },
                            WebWindowId: WEB_WINDOW_ID
                        }
                    );			            
    	            
                    Kaseya.Presentation.Services.MakeEventRequest(eventRequest, function(r) {
                        var eventResponse = Ext.JSON.decode(r);				                
    	                				                				                   	                
                        InsertScreen(
                        { 
                            xtype: 'kscreen',
                            data: eventResponse.Data,
                            controls: eventResponse.Controls,
                            customParams: ((userData && userData.currentLoadConfig && userData.currentLoadConfig.customParams)?userData.currentLoadConfig.customParams:{})
                        }, 
                        Ext.getCmp('CenterPanel')
                        );				                
                    });
				} 
				else if (_node.data.editableContextScreen) {
			        showLoading = true;
			        
                    // save the last navigation item
			        MessageSysProvider.TouchScreen(WEB_WINDOW_ID, _node.data.funcListID, function(e, response) {
			            var resp = Ext.JSON.decode(e);
			            HandleResponseHeader(resp.header)
			        });                    
                    
                    // create the interaction controller with the name "editableContextScreen"
                    var interactionController = CreateInteractionControllerConfig(_node.data.conduit, _node.data.plugin, _node.data.className, null, null, PAGE_ID, 'editableContextScreen', { host: 'FORM', funcListID: _node.data.funcListID, editableContextScreen: true});
			    
				    // execute the interaction controller instead of the normal life-cycle (getscreen, getdatasource, etc)
				    ControllerConfigurationStart(WEB_WINDOW_ID, ACTION_URL, interactionController, null, true, PAGE_ID, null);		    				    
				}
				else {    				                   				    
				    showLoading = true;
				    _node.data.dataProvider.GetScreen(_node.data.funcListID, PAGE_ID, '', userData.currentLoadConfig.filterName || null, userData.currentLoadConfig.dimensions ? Ext.JSON.encode(userData.currentLoadConfig.dimensions) : null, userData.currentLoadConfig.resetFilter || false, userData.currentLoadConfig.customParams ? Ext.JSON.encode(userData.currentLoadConfig.customParams) : null, WEB_WINDOW_ID, OnGetScreenSuccessPort, _node);
				}
				
				if (showLoading && !_node.data.editableContextScreen) {
                    var cp = Ext.getCmp('CenterPanel');	
                    if (cp && cp.el) {                        					
                        cp.el.mask(Ext.LoadMask.prototype.msg.replace("...", " " + _node.data.text + "..."));
                    }					    
				}
			}
		}
	}
	else {
		// screen is already built, so just reload selector
		reloadSelector(PAGE_ID, true);
	}
	//	}
	mod = null;
	userData = null;
}

/**
 * Logs the current user off and redirects them to the main logon page.
 */
function Logoff(_url){
    var vp = Ext.getCmp('PageShellViewPort');
    if (vp) {
        var cp = Ext.getCmp('CenterPanel');
        if (cp && cp.el && cp.el.isMasked()) {
            cp.el.unmask();
        }

        vp.el.mask(Ext.ux.LangMgr.User.LoggingOff + '...');
    }

    Ext.Ajax.request({
		url: ACTION_URL,
		params: {
			handlerClassName: 'Kaseya.WebFoundation.Actions.LogoffInteractionDialogAction',
			behavior: 'START',
			actionid: 'logoff',
			referringWebWindowId: WEB_WINDOW_ID,
			redirectURL: typeof(_url) == 'string' ? _url : null
		},
		success: function(_response, _options){
			document.cookie = 'sessionId=-1; path=/';
			top.location = _options.params.redirectURL || logoffURL || "/mainLogon.asp?logout=" + String(Math.random());
		},
		failure: function(_response, _options){
			top.location = "/mainLogon.asp?logout=" + String(Math.random());
		}
		
	});
}

function InvokePseudoController(_objectName, _controllerName, _controllerConfig, _recordId, _embedded, _windowId){
	var markedObjects = {
		items: [{
			id: _objectName,
			selections: {
				items: [{
					id: _recordId
				}]
			},
			selectAll: false
		}]
	};
	
	var fakeButton = {};
	fakeButton.initialConfig = {};
	fakeButton.pageId = GenerateUniqueActionId();
	fakeButton.dataObjectName = _objectName;
	fakeButton.initialConfig.referringWebWindowId = _windowId;
	fakeButton.initialConfig.controllerConfiguration = {};
	
	Ext.apply(fakeButton.initialConfig.controllerConfiguration, _controllerConfig);
	
	if (!_embedded) {
		fakeButton.initialConfig.website = '/vsaPres/Web20/actions/ClassWindowInteractionDialog.aspx'
		fakeButton.initialConfig.controllerConfiguration.host = 'CLASSIC_WINDOW';
	}
	else {
		fakeButton.initialConfig.website = '/vsaPres/Web20/actions/InteractionDialog.ashx';
		fakeButton.initialConfig.controllerConfiguration.host = 'EMBEDDED_WINDOW';
	}
	
	fakeButton.initialConfig.controllerConfiguration.itemFuncListId = null;
	
	if (!_embedded && _windowId) {
        fakeButton.windowId = _windowId;
    }
	
	ControllerStart(fakeButton, markedObjects, true);
}

function InvokeController(_objectName, _controllerName, _recordId, _embedded, _windowId){
	// obtain the controller with a call into json.ashx
	MessageSysProvider.GetController(WEB_WINDOW_ID, !_embedded, _objectName, _controllerName, function(e, _response){
		if (_response && _response.status) {
			try {
				// verify that the response was successful.  if not, toss up the error
				var r = Ext.JSON.decode(_response.result);
				if (r && r.success && HandleResponseHeader(r.header)) {
					var markedObjects = {
						'items': [{
							'id': '',
							'selections': {
								'items': [{
									'id': ''
								}]
							},
							'selectAll': false
						}]
					};
					
					if (Ext.isIE) {
					    markedObjects.items[0].selections.length = 1; // required by EncodeMarkedObjects in IE
					}
					
					markedObjects.items[0].id = _objectName;
					markedObjects.items[0].selections.items[0].id = _recordId;
					
					var fakeButton = {};
					fakeButton.initialConfig = {};
					fakeButton.pageId = GenerateUniqueActionId();
					fakeButton.dataObjectName = _objectName;
					fakeButton.initialConfig.dataObjectName = _objectName;
					fakeButton.initialConfig.pageId = fakeButton.pageId;
					fakeButton.initialConfig.referringWebWindowId = r.data.referringWebWindowId;
					fakeButton.initialConfig.controllerConfiguration = r.data.controllerConfiguration;
					
					if (!_embedded) {
						fakeButton.initialConfig.website = '/vsaPres/Web20/actions/ClassWindowInteractionDialog.aspx'
						fakeButton.initialConfig.controllerConfiguration.host = 'CLASSIC_WINDOW';
					}
					else {
						fakeButton.initialConfig.website = '/vsaPres/Web20/actions/InteractionDialog.ashx';
						fakeButton.initialConfig.controllerConfiguration.host = 'EMBEDDED_WINDOW';
					}
					
					fakeButton.initialConfig.controllerConfiguration.itemFuncListId = null;
					
					if (!_embedded && _windowId) {
					    fakeButton.windowId = _windowId;
					}
					
					ControllerStart(fakeButton, markedObjects, true);
				}
				else {
					DisplayResponseObject(r);
				}
			} 
			catch (_ex) {
				if (_response && _response.responseText) {
                    _ex.responseText = _response.responseText;
                }
				DisplayException(_ex);
			}
		}
		else {
			AddDebugger();
		}
	});
}

function GetControllerParams(_btnClicked, _markedObjects, _sticky) {    
    var params = {};
    if (_btnClicked.initialConfig.pageId && _btnClicked.initialConfig.dataIslandId && _btnClicked.initialConfig.dataObjectName) {
        params.selectedRecords = Ext.JSON.encode(PageMgrFinder().getSelections(_btnClicked.initialConfig.pageId, _btnClicked.initialConfig.dataIslandId, _btnClicked.initialConfig.dataObjectName).items);
    }

	var mo = _markedObjects || PageMgrFinder().getSelectionObjects( _btnClicked.initialConfig.pageId, _btnClicked.initialConfig.dataIslandId);
	if (mo){
	    //KERBE: This code is for a multi-tree context screen. It will get the marked objects from the selector tree and pass those along with the selection marked objects.
	    if(_btnClicked.initialConfig.pageId === 'staticPanelId'){
	        var treeMo = PageMgrFinder().getSelectionObjects( PAGE_ID, 'selectorIsland').items[0];
	        mo.add(treeMo);
	    }
		params.markedObjects = EncodeMarkedObjects(mo);
	}

    params.actionArgument = _btnClicked.initialConfig.controllerConfiguration.argument;
    params.conduit = _btnClicked.initialConfig.controllerConfiguration.conduit;
    params.classname = _btnClicked.initialConfig.controllerConfiguration.className;
    params.plugin = _btnClicked.initialConfig.controllerConfiguration.plugin;
    params.handlerClassName = _btnClicked.initialConfig.controllerConfiguration.handlerClassName;
    params.behavior = _btnClicked.initialConfig.controllerConfiguration.behavior;
    params.name = _btnClicked.initialConfig.controllerConfiguration.name;
    
    if (_btnClicked.initialConfig.controllerConfiguration.host == "PANEL") {
        params.host = _btnClicked.initialConfig.controllerConfiguration.initialHost;
    }
    else {
        params.host = _btnClicked.initialConfig.controllerConfiguration.host;
    }

    params.properties = Ext.JSON.encode(_btnClicked.initialConfig.controllerConfiguration.ControllerProperties);
    params.pageName = _btnClicked.initialConfig.controllerConfiguration.pageName;
    params.includeMarkedObjects = _btnClicked.initialConfig.controllerConfiguration.includeMarkedObjects;
    params.includeWindowId = _btnClicked.initialConfig.controllerConfiguration.includeWindowId;
    params.markedObjectParamName = _btnClicked.initialConfig.controllerConfiguration.markedObjectParamName;
    params.preControllerParamName = _btnClicked.initialConfig.controllerConfiguration.preControllerParamName;
    params.pageId = _btnClicked.initialConfig.pageId;
    params.linkedSpecified = _btnClicked.initialConfig.controllerConfiguration.linkedSpecified;
    params.linked = _btnClicked.initialConfig.controllerConfiguration.linked;
    params.useLinkId = _btnClicked.initialConfig.controllerConfiguration.useLinkId;
    
    if (_btnClicked.initialConfig.controllerConfiguration.markedObjectName) {
        params.markedObjectName = _btnClicked.initialConfig.controllerConfiguration.markedObjectName;
    }
    
    if (_btnClicked.initialConfig.controllerConfiguration.pageLocation) {
        params.pageLocation = _btnClicked.initialConfig.controllerConfiguration.pageLocation;
    }

    params.itemFuncListId = _btnClicked.initialConfig.controllerConfiguration.itemFuncListId;
    //TODO: Remove this from the params
    params.clearRecords = true;
    params.dataObjectName = _btnClicked.initialConfig.dataObjectName;
    params.allowms = false;

    // tack on the word child to the action id if it has a parent so its easily recogizable as a child action.
    var uid = GenerateUniqueActionId() + (_btnClicked.initialConfig.parentid ? '_child' : '');

    params.actionid = uid;
    params.dataIslandId = uid;
    
    var islandId = _btnClicked.initialConfig.pageId;
    if (_btnClicked.initialConfig.controllerConfiguration.host == "FORM")
    {
        islandId = "selectionIsland";
    }
    
    var model = PageMgrFinder().getModel(_btnClicked.initialConfig.pageId,  islandId);
    params.dataIsland = Ext.JSON.encode(model);
    
    params.parentid = _btnClicked.initialConfig.parentid;
    params.referringWebWindowId = _btnClicked.initialConfig.referringWebWindowId;
    
    if (_btnClicked.initialConfig && _btnClicked.initialConfig.controllerConfiguration && _btnClicked.initialConfig.controllerConfiguration.PreController) {
        params.preactionType = _btnClicked.initialConfig.controllerConfiguration.PreController.type;
        params.preactionInputValue = _btnClicked.initialConfig.preactionInputValue;
        params.preactionAffirmativeResponse = _btnClicked.initialConfig.preactionAffirmativeResponse;
    }

    return params;
}

/**
 * Starts a controller based on the passed button and its initial configuration
 * 
 * If marked objects are passed for a temporary action (like a view) then this will
 * send the temporary marked objects as specified instead of those maintained by the
 * application in the page manager.
 * 
 * If the controller should not be sticky, then we'll remove the close button from
 * the window and dismiss it when the mouse leaves the window.  Defaults to true.
 * 
 * @param {Object} _btnClicked
 * @param {Object} _markedObjects (optional)
 * @param {Object} _sticky (optional)
 */
function ControllerStart( _btnClicked, _markedObjects, _sticky ) {
    var params = GetControllerParams(_btnClicked, _markedObjects, _sticky);
    
    var uid = params.dataIslandId;
    var sticky = (_sticky == null) ? true : _sticky;
	
	LogToConsole('Starting Controller ' + params.name);
	LogToConsole(params);
	
	var startControllerClass = null;

    switch(_btnClicked.initialConfig.controllerConfiguration.host) {
		case 'FORM': {					
            startControllerClass = 'Kaseya.web.startcontrollers.FormController';		   
		    break;
		}		
		case "EMBEDDED_WINDOW": {
            startControllerClass = 'Kaseya.web.startcontrollers.EmbeddedWindowController';
            _sticky = true;
			break;
        }
		case "WINDOWLESS":
		case "DOWNLOAD": {
            startControllerClass = 'Kaseya.web.startcontrollers.WindowlessController';         
		    break;
        }
		case "BACKGROUND": {
            startControllerClass = 'Kaseya.web.startcontrollers.BackgroundController';
			break;
        }
		case "SINGLE_USE_CLASSIC_WINDOW":
		case "CLASSIC_WINDOW": {
            startControllerClass = 'Kaseya.web.startcontrollers.ClassicWindowController';          
		    break;
        }
		default: {
			AddDebugger();
			break;
	    }
    }   

    if (startControllerClass) {
        var startController = Ext.create(startControllerClass, {
            actionConfig: _btnClicked,
            sticky: _sticky,
            params: params,
            uid: uid
        });

        startController.launch();	
    }
}

function popupsBlocked() {
    // stole this text from /inc/popupAlert.js, Server.Execute adds illegal characters
	alert(Ext.ux.LangMgr.PopupBlockerWarning.message + "\r\n\r\n" +
	Ext.ux.LangMgr.SystemInterferenceWarning.message +
	"\r\n" +
	Ext.ux.LangMgr.EnablePopupsMessage.message);
}

/**
 * Resets User Preferences on the web server and clears any existing cookie information in the browser.
 */
function ResetUserPreferences(){
	MessageSysProvider.ResetUserPreferences(WEB_WINDOW_ID, function(e, _response){
		if (_response && _response.status) {
			Ext.state.Manager.getProvider().initState({});
		}
		else {
			AddDebugger();
		}

        var modTree = Ext.getCmp('modTree');
        if (modTree) {
            modTree.resetToBasic();
        }
	});
}

function LogToConsole(){
	if (showConsole) {
		if (arguments && arguments.length > 0) {
			for (var i = 0; i < arguments.length; i++) {
				if (typeof arguments[i] == 'string' || typeof arguments[i] == 'number' || Ext.isDate(arguments[i])) {
					Ext.log(arguments[i]);
				}
				else {
					for (key in arguments[i]) { // TODO: use Ext.iterate
						if (typeof(arguments[i][key]) == 'string' || typeof(arguments[i][key]) == 'number' || Ext.isDate(arguments[i][key])) {
							Ext.log(key + ':  ' + arguments[i][key]);
                        }
						else if (typeof(arguments[i][key]) == 'object') {
						    //Ext.log(key + ':  ' + arguments[i][key]);
						    //LogObjectToConsole(arguments[i][key]);
						}
					}
				}
			}
		}
	}
}

function LogObjectToConsole(_o){
	if (showConsole) {
		if (_o) {
			for (key in _o) { // TODO: use Ext.iterate
				if (typeof _o[key] == 'string' || typeof _o[key] == 'number' || Ext.isDate(_o[key])) {
					Ext.log(key + ':  ' + _o[key]);
				}
				else if (typeof(_o[key]) == 'object') {
					LogObjectToConsole(key);
				}
			}
		}
	}
}

function getHelpTopic(topicId){
	topicPage = buildShellVersionHelpLink(topicId);
	doHelpWin(topicPage);
}

function doHelpWin(helpLink){
	helpWin = null;
	windowUrl = helpLink;
	helpWidth = 760;
	helpHeight = 600;
	helpTop = 40;
	helpLeft = 50;
	
	helpWin = window.open(windowUrl, "helpWin", "scrollbars,toolbar,width=" + helpWidth + ",height=" + helpHeight + ",top=" + helpTop + ",left=" + helpLeft + ",resizable=yes");
	if (helpWin) {
        helpWin.focus();
    }
}

function buildShellVersionHelpLink(topicId){
	helpTopicId = String(topicId);
	if (helpTopicId.length == 0) {
		helpTopicId = "270";
	}

	var user = PageMgrFinder().getUser();
	var topicPage = user.helpUrl + '/' + user.currentCultureCode + '/' + user.currentHelpContext.helpModule + '/' + user.currentHelpContext.helpVersion + '/index.htm?toc.htm?' + helpTopicId + '.htm';
	
    return topicPage;
}

function specialHtmlDecode(_string){
	var s = Ext.htmlDecode(_string);
	s = s.replace(/&apos;/g, "'");
	
    return s;
}

function findGridColumnColorMetaField(value, p, record, dataIndex){
	if (record.store) {
	    var g = Ext.getCmp(record.store.gridId);
	    if (g && g.metaComponents) {
		    return g.findColorMetaField(g.getMetaObject())
        }
	}
	
    return null;
}

function findGridColumnMetaField(value, p, record, dataIndex){
	if (record.store) {
	    var g = Ext.getCmp(record.store.gridId);
	    if (g && g.metaComponents && dataIndex) {
		    return g.findMetaField(g.objectName, dataIndex, g.metaComponents)
        }
	}
    
    return null;
}

function findGridColumnRenderer(value, p, record, dataIndex){
	if (record.store) {
	    var g = Ext.getCmp(record.store.gridId);
		if (dataIndex && g) {			
		    return g.findGridColumnRenderer(dataIndex)
        }
	}
	
    return null;
}

function appItemCount(_visibleOnly){
	var user = PageMgrFinder().getUser();
	var ct = 0;
	
    if (user){
		for (var m=0;  m < user.applications[0].modules.length; m++) {
			if (!_visibleOnly || user.applications[0].modules[m].visible){
				for (var f=0; f < user.applications[0].modules[m].folders.length; f++) {
					for (var i=0; i < user.applications[0].modules[m].folders[f].items.length; i++) {
						ct++;
					}
				}
			}
		}
	}

	return ct;
}

function stopAutotestNavigator() {
}

function autotestNavigator(_interval, nav) {
}

/**
* this is a duplicate of ext-overrides toBoolAttribute but we needed it to be more global.
* Returns the boolean representation of the param.  This will do things like convert the string value to a boolean, and if undefined, set to false.
* @param {Object} _value the current value of the parameter.
* @return {Object} the boolean representation of the value provided.
*/
function convertToBool (_value) {
    var result = false;
    if (Ext.isBoolean(_value)) {
        result = _value;
    }
    else if (Ext.isString(_value)) {
        if (_value && _value.toLowerCase() == 'true') {
            result = true;
        }
    }

    return result;
}

function CreateInteractionControllerConfig(conduit, plugin, className, dataIslandId, dataObjectName, pageId, name, optionsConfig) {
    var markedObjects = { items: [] };    
    
    // set defaults that can be overridden with optionsConfig
    var interactionControllerConfig = {
        accessRight: 'UNDEFINED',
        behavior: "START",
        caption: '',
        className: className,
        cls: 'x-btn-text-icon',
        conduit: conduit,
        controllerConfiguration: {},
        controllerVAlign: 'TOP',
        dataIslandId: dataIslandId,
        dataObjectName: dataObjectName,
        disabled: false,
        displayToolbarText: false,
        enabled: true,
        funcListID: '',
        handler: function(btn) {
            var mo = (optionsConfig && optionsConfig.markedObjects) ? optionsConfig.markedObjects : markedObjects;
            ControllerStart(btn, mo, true)
        },
        handlerClassName: 'Kaseya.WebFoundation.Actions.InteractionDialogAction.cs',
        hidden: false,
        host: 'EMBEDDED_WINDOW',
        icon: AdjustSSLPath('/vsaPres/App_Themes/0/images/size16/actions/action.png'),
        image: 'action',
        initialEnabledState: true,
        isDefault: false,
        isToggle: false,
        linked: false,
        maxSelectionRequirement: 'N',
        menuContainer: false,
        minSelectionRequirement: '0',
        name: name,
        pageId: pageId,
        plugin: plugin,
        referringWebWindowId: WEB_WINDOW_ID,
        rightClickFlag: false,
        suppressProcessIndicator: false,
        text: '',
        tooltip: {autoHide: true, text: ''},
        validate: false,      
        windowHeight: 1800,
        windowTitle: '',
        windowWidth: 1800
    };
   
    if (optionsConfig) {
        Ext.apply(interactionControllerConfig, optionsConfig); // overwrite any properties specified in config options
    }
    
    var c = Ext.clone(interactionControllerConfig); // do not propogate controllerConfiguration, as it will create circular references
    delete c.controllerConfiguration;

    Ext.applyIf(interactionControllerConfig.controllerConfiguration, c);
   
    interactionControllerConfig.tooltip.text = interactionControllerConfig.text;   
    interactionControllerConfig.website = ((interactionControllerConfig.host == 'CLASSIC_WINDOW' || interactionControllerConfig.host == 'SINGLE_USE_CLASSIC_WINDOW') ? CLASSIC_ACTION_URL : ACTION_URL);
      
    return interactionControllerConfig;     
}

function reservedWordValidator(value) {
    var isValid;

    switch(value){
        case '__defineGetter__':
        case '__defineSetter__':
        case '__lookupGetter__':
        case '__lookupSetter__':
        case 'constructor':
        case 'hasOwnProperty':
        case 'isPrototypeOf':
        case 'propertyIsEnumerable':
        case 'toLocaleString':
        case 'toString':
        case 'valueOf':
            isValid = false;
            break;
        default:
            isValid = true;
            break; 
    }

    if (isValid === true){
        return true;
    }
   
    return String.format(Ext.ux.LangMgr.ReservedWordError.message, value);
}

// if IE browser and SSL, IE will result in mixed secure and non secure content when adding toolbar
// buttons with a relative url.  To resolve this, make the icon url absolute.
function AdjustSSLPath(imagePath) {
    var wRoot = '';
    if (Ext.isIE && Ext.isSecure) {
        wRoot = top.location.href.substr(0, top.location.href.indexOf(top.location.pathname));
    }
    
    return wRoot + imagePath;
}

/**
 * Adds endsWith functionality to all strings
 * @param {Object} suffix
 * @return true if the string ends with the provided suffix, false otherwise
 */
if (!String.prototype.endsWith) {
	String.prototype.endsWith = function(suffix){
		var startPos = this.length - suffix.length;
		if (startPos < 0) {
			return false;
		}
		return (this.lastIndexOf(suffix, startPos) == startPos);
	};
}

if (!String.prototype.startsWith) {
	String.prototype.startsWith = function(str){
		return (this.match("^" + str) == str)
	}
}

if (!String.prototype.trim) {
	String.prototype.trim = function(){
		return this.replace(/^\s+|\s+$/g, "");
	};
}

if (!String.prototype.ltrim) {
	String.prototype.ltrim = function(){
		return this.replace(/^\s+/, "");
	};
}

if (!String.prototype.rtrim) {
	String.prototype.rtrim = function(){
		return this.replace(/\s+$/, "");
	};
}